diff --git a/core/types/tx_access_list.go b/core/types/tx_access_list.go index 4f8160b754..730a77b752 100644 --- a/core/types/tx_access_list.go +++ b/core/types/tx_access_list.go @@ -44,46 +44,6 @@ func (al AccessList) StorageKeys() int { return sum } -// WithoutAuthorizations removes authorities of valid authorizations from the resulting array, -// because such addresses will be added to the access list automatically, so there is no reason to return them -// (exception if they have not empty storage keys list). -func (al AccessList) WithoutAuthorizations(chainID *big.Int, authorizations []SetCodeAuthorization) AccessList { - validAuthorities := make(map[common.Address]struct{}, len(authorizations)) - - for _, auth := range authorizations { - // According to stateTransition.applyAuthorization(), - // authority address will be added to the access list if the next three conditions are satisfied. - if !auth.ChainID.IsZero() && auth.ChainID.CmpBig(chainID) != 0 { - continue - } - - if auth.Nonce+1 < auth.Nonce { - continue - } - - authority, err := auth.Authority() - if err != nil { - continue - } - - validAuthorities[authority] = struct{}{} - } - - if len(validAuthorities) == 0 { - return al - } - - output := make(AccessList, 0, len(validAuthorities)) - for _, accessTuple := range al { - // Keep this address if it is not present in valid authorities map, or if it contains not empty storage keys. - if _, ok := validAuthorities[accessTuple.Address]; !ok || len(accessTuple.StorageKeys) != 0 { - output = append(output, accessTuple) - } - } - - return output -} - // AccessListTx is the data of EIP-2930 access list transactions. type AccessListTx struct { ChainID *big.Int // destination chain ID diff --git a/core/types/tx_access_list_test.go b/core/types/tx_access_list_test.go deleted file mode 100644 index a0433114be..0000000000 --- a/core/types/tx_access_list_test.go +++ /dev/null @@ -1,58 +0,0 @@ -package types - -import ( - "crypto/ecdsa" - "math" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/holiman/uint256" - "github.com/stretchr/testify/require" -) - -func TestAccessListWithoutAuthorizations(t *testing.T) { - generateKey := func(t *testing.T) *ecdsa.PrivateKey { - key, err := crypto.GenerateKey() - require.NoError(t, err) - return key - } - - prepareAuth := func(t *testing.T, auth SetCodeAuthorization, key *ecdsa.PrivateKey) SetCodeAuthorization { - signature, err := crypto.Sign(auth.sigHash().Bytes(), key) - require.NoError(t, err) - auth.R.SetBytes(signature[0:32]) - auth.S.SetBytes(signature[32:64]) - auth.V = signature[64] - return auth - } - - targetChainID := uint256.NewInt(1) - key1, key2, key3, key4, key5 := generateKey(t), generateKey(t), generateKey(t), generateKey(t), generateKey(t) - - authorizationWithInvalidSignature := SetCodeAuthorization{ChainID: *targetChainID} - authorizationWithInvalidChainID := prepareAuth(t, SetCodeAuthorization{ChainID: *uint256.NewInt(2)}, key1) - authorizationWithNonceOverflow := prepareAuth(t, SetCodeAuthorization{ChainID: *targetChainID, Nonce: math.MaxUint64}, key2) - validAuthorizationForAddressWithStorage := prepareAuth(t, SetCodeAuthorization{ChainID: *targetChainID}, key3) - validAuthorizationForAddressWithoutStorage1 := prepareAuth(t, SetCodeAuthorization{}, key4) - validAuthorizationForAddressWithoutStorage2 := prepareAuth(t, SetCodeAuthorization{ChainID: *targetChainID}, key5) - - accessTuple1 := AccessTuple{Address: crypto.PubkeyToAddress(key1.PublicKey)} - accessTuple2 := AccessTuple{Address: crypto.PubkeyToAddress(key2.PublicKey)} - accessTuple3 := AccessTuple{Address: crypto.PubkeyToAddress(key3.PublicKey), StorageKeys: []common.Hash{{}}} - accessTuple4 := AccessTuple{Address: crypto.PubkeyToAddress(key4.PublicKey), StorageKeys: []common.Hash{}} // should be deleted - accessTuple5 := AccessTuple{Address: crypto.PubkeyToAddress(key5.PublicKey)} // should be deleted - accessTuple6 := AccessTuple{Address: common.Address{1}} - - al := AccessList{accessTuple1, accessTuple2, accessTuple3, accessTuple4, accessTuple5, accessTuple6} - - require.Equal(t, al, al.WithoutAuthorizations(targetChainID.ToBig(), nil), "AccessList should not be modified without authorizations") - require.Equal(t, AccessList{accessTuple1, accessTuple2, accessTuple3, accessTuple6}, al.WithoutAuthorizations(targetChainID.ToBig(), []SetCodeAuthorization{ - authorizationWithInvalidSignature, - authorizationWithInvalidChainID, - authorizationWithNonceOverflow, - validAuthorizationForAddressWithStorage, - validAuthorizationForAddressWithoutStorage1, - validAuthorizationForAddressWithoutStorage2, - })) -} diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index e8231461b0..0d51f40522 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -103,16 +103,10 @@ type AccessListTracer struct { // NewAccessListTracer creates a new tracer that can generate AccessLists. // An optional AccessList can be specified to occupy slots and addresses in // the resulting accesslist. -func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompiles []common.Address) *AccessListTracer { - excl := map[common.Address]struct{}{ - from: {}, to: {}, - } - for _, addr := range precompiles { - excl[addr] = struct{}{} - } +func NewAccessListTracer(acl types.AccessList, addressesToExclude map[common.Address]struct{}) *AccessListTracer { list := newAccessList() for _, al := range acl { - if _, ok := excl[al.Address]; !ok { + if _, ok := addressesToExclude[al.Address]; !ok { list.addAddress(al.Address) } for _, slot := range al.StorageKeys { @@ -120,7 +114,7 @@ func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompi } } return &AccessListTracer{ - excl: excl, + excl: addressesToExclude, list: list, } } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 2185c8a597..0a7ade5422 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1165,10 +1165,27 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH // Retrieve the precompiles since they don't need to be added to the access list precompiles := vm.ActivePrecompiles(b.ChainConfig().Rules(header.Number, isPostMerge, header.Time)) + // addressesToExclude contains sender, receiver, precompiles and valid authorizations + addressesToExclude := map[common.Address]struct{}{args.from(): {}, to: {}} + for _, addr := range precompiles { + addressesToExclude[addr] = struct{}{} + } + + for _, auth := range args.AuthorizationList { + // Duplicating stateTransition.validateAuthorization() logic + if (!auth.ChainID.IsZero() && auth.ChainID.CmpBig(b.ChainConfig().ChainID) != 0) || auth.Nonce+1 < auth.Nonce { + continue + } + + if authority, err := auth.Authority(); err == nil { + addressesToExclude[authority] = struct{}{} + } + } + // Create an initial tracer - prevTracer := logger.NewAccessListTracer(nil, args.from(), to, precompiles) + prevTracer := logger.NewAccessListTracer(nil, addressesToExclude) if args.AccessList != nil { - prevTracer = logger.NewAccessListTracer(*args.AccessList, args.from(), to, precompiles) + prevTracer = logger.NewAccessListTracer(*args.AccessList, addressesToExclude) } for { if err := ctx.Err(); err != nil { @@ -1185,7 +1202,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH msg := args.ToMessage(header.BaseFee, true, true) // Apply the transaction with the access list tracer - tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles) + tracer := logger.NewAccessListTracer(accessList, addressesToExclude) config := vm.Config{Tracer: tracer.Hooks(), NoBaseFee: true} evm := b.GetEVM(ctx, statedb, header, &config, nil) @@ -1202,7 +1219,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.ToTransaction(types.LegacyTxType).Hash(), err) } if tracer.Equal(prevTracer) { - return accessList.WithoutAuthorizations(b.ChainConfig().ChainID, msg.SetCodeAuthorizations), res.UsedGas, res.Err, nil + return accessList, res.UsedGas, res.Err, nil } prevTracer = tracer }