pre-derive authorities

This commit is contained in:
alan 2025-02-18 10:24:49 +08:00 committed by lightclient
parent 135d9be3d8
commit 95c732cfac
No known key found for this signature in database
GPG key ID: 657913021EF45A6A
6 changed files with 93 additions and 36 deletions

View file

@ -156,6 +156,7 @@ type Message struct {
BlobGasFeeCap *big.Int BlobGasFeeCap *big.Int
BlobHashes []common.Hash BlobHashes []common.Hash
SetCodeAuthorizations []types.SetCodeAuthorization SetCodeAuthorizations []types.SetCodeAuthorization
AuthorityCache *types.AuthorityCache
// 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.
@ -185,6 +186,7 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In
Data: tx.Data(), Data: tx.Data(),
AccessList: tx.AccessList(), AccessList: tx.AccessList(),
SetCodeAuthorizations: tx.SetCodeAuthorizations(), SetCodeAuthorizations: tx.SetCodeAuthorizations(),
AuthorityCache: tx.AuthorityCache(),
SkipNonceChecks: false, SkipNonceChecks: false,
SkipTransactionChecks: false, SkipTransactionChecks: false,
BlobHashes: tx.BlobHashes(), BlobHashes: tx.BlobHashes(),
@ -504,9 +506,13 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
// Apply EIP-7702 authorizations. // Apply EIP-7702 authorizations.
if msg.SetCodeAuthorizations != nil { if msg.SetCodeAuthorizations != nil {
for _, auth := range msg.SetCodeAuthorizations { for i, auth := range msg.SetCodeAuthorizations {
// Note errors are ignored, we simply skip invalid authorizations here. // Note errors are ignored, we simply skip invalid authorizations here.
st.applyAuthorization(&auth) authority, err := msg.AuthorityCache.Authority(i)
if err != nil {
continue
}
st.applyAuthorization(&auth, authority)
} }
} }
@ -574,7 +580,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.SetCodeAuthorization) (authority common.Address, err error) { func (st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorization, preDerivedAuthority common.Address) (authority common.Address, err error) {
// Verify chain ID is null or equal to current chain ID. // Verify chain ID is null or equal to current chain ID.
if !auth.ChainID.IsZero() && auth.ChainID.CmpBig(st.evm.ChainConfig().ChainID) != 0 { if !auth.ChainID.IsZero() && auth.ChainID.CmpBig(st.evm.ChainConfig().ChainID) != 0 {
return authority, ErrAuthorizationWrongChainID return authority, ErrAuthorizationWrongChainID
@ -583,11 +589,9 @@ func (st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorizatio
if auth.Nonce+1 < auth.Nonce { if auth.Nonce+1 < auth.Nonce {
return authority, ErrAuthorizationNonceOverflow return authority, ErrAuthorizationNonceOverflow
} }
// Validate signature values and recover authority.
authority, err = auth.Authority() authority = preDerivedAuthority
if err != nil {
return authority, fmt.Errorf("%w: %v", ErrAuthorizationInvalidSignature, err)
}
// Check the authority account // Check the authority account
// 1) doesn't have code or has exisiting delegation // 1) doesn't have code or has exisiting delegation
// 2) matches the auth's nonce // 2) matches the auth's nonce
@ -605,8 +609,8 @@ func (st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorizatio
} }
// applyAuthorization applies an EIP-7702 code delegation to the state. // applyAuthorization applies an EIP-7702 code delegation to the state.
func (st *stateTransition) applyAuthorization(auth *types.SetCodeAuthorization) error { func (st *stateTransition) applyAuthorization(auth *types.SetCodeAuthorization, preDerivedAuthority common.Address) error {
authority, err := st.validateAuthorization(auth) authority, err := st.validateAuthorization(auth, preDerivedAuthority)
if err != nil { if err != nil {
return err return err
} }

View file

@ -519,20 +519,25 @@ func (tx *Transaction) SetCodeAuthorities() []common.Address {
if !ok { if !ok {
return nil return nil
} }
var ( if authorityCache := setcodetx.authorityCache.Load(); authorityCache != nil {
marks = make(map[common.Address]bool) return authorityCache.authorities
auths = make([]common.Address, 0, len(setcodetx.AuthList))
)
for _, auth := range setcodetx.AuthList {
if addr, err := auth.Authority(); err == nil {
if marks[addr] {
continue
}
marks[addr] = true
auths = append(auths, addr)
}
} }
return auths cache := ToAuthorityCache(setcodetx.AuthList)
setcodetx.authorityCache.Store(cache)
return cache.authorities
}
func (tx *Transaction) AuthorityCache() *AuthorityCache {
setcodetx, ok := tx.inner.(*SetCodeTx)
if !ok {
return nil
}
if authorityCache := setcodetx.authorityCache.Load(); authorityCache != nil {
return authorityCache
}
cache := ToAuthorityCache(setcodetx.AuthList)
setcodetx.authorityCache.Store(cache)
return cache
} }
// SetTime sets the decoding time of a transaction. This is used by tests to set // SetTime sets the decoding time of a transaction. This is used by tests to set

View file

@ -65,19 +65,70 @@ type SetCodeTx struct {
V *uint256.Int V *uint256.Int
R *uint256.Int R *uint256.Int
S *uint256.Int S *uint256.Int
// caches
authorityCache atomic.Pointer[AuthorityCache]
}
func ToAuthorityCache(authList []SetCodeAuthorization) *AuthorityCache {
var (
marks = make(map[common.Address]bool)
auths = make([]common.Address, 0, len(authList))
invalid []invalidAuth // empty since it's expected to be empty most of the time
)
for i, auth := range authList {
if addr, err := auth.Authority(); err == nil {
if marks[addr] {
continue
}
marks[addr] = true
auths = append(auths, addr)
} else {
invalid = append(invalid, invalidAuth{index: i, error: err})
}
}
return &AuthorityCache{authorities: auths, invalidAuths: invalid}
}
type AuthorityCache struct {
authorities []common.Address
invalidAuths []invalidAuth
}
type invalidAuth struct {
index int
error error
}
func (ac *AuthorityCache) Authority(i int) (common.Address, error) {
indexToSub := 0
for _, invalid := range ac.invalidAuths {
if i == invalid.index {
return common.Address{}, invalid.error
}
if i > invalid.index {
indexToSub++
continue
}
break
}
targetIndex := i - indexToSub
if targetIndex < 0 || targetIndex >= len(ac.authorities) {
return common.Address{}, errors.New("index out of range")
}
return ac.authorities[i-indexToSub], nil
} }
//go:generate go run github.com/fjl/gencodec -type SetCodeAuthorization -field-override authorizationMarshaling -out gen_authorization.go //go:generate go run github.com/fjl/gencodec -type SetCodeAuthorization -field-override authorizationMarshaling -out gen_authorization.go
// SetCodeAuthorization 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 SetCodeAuthorization struct { type SetCodeAuthorization struct {
ChainID uint256.Int `json:"chainId" gencodec:"required"` ChainID uint256.Int `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"`
V uint8 `json:"yParity" gencodec:"required"` V uint8 `json:"yParity" gencodec:"required"`
R uint256.Int `json:"r" gencodec:"required"` R uint256.Int `json:"r" gencodec:"required"`
S uint256.Int `json:"s" gencodec:"required"` S uint256.Int `json:"s" gencodec:"required"`
authority atomic.Pointer[common.Address] `json:"-"`
} }
// field type overrides for gencodec // field type overrides for gencodec
@ -137,7 +188,6 @@ func (a *SetCodeAuthorization) Authority() (common.Address, error) {
} }
var addr common.Address var addr common.Address
copy(addr[:], crypto.Keccak256(pub[1:])[12:]) copy(addr[:], crypto.Keccak256(pub[1:])[12:])
a.authority.Store(&addr)
return addr, nil return addr, nil
} }

View file

@ -185,11 +185,7 @@ func (t *prestateTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction
t.lookupAccount(env.Coinbase) t.lookupAccount(env.Coinbase)
// Add accounts with authorizations to the prestate before they get applied. // Add accounts with authorizations to the prestate before they get applied.
for _, auth := range tx.SetCodeAuthorizations() { for _, addr := range tx.SetCodeAuthorities() {
addr, err := auth.Authority()
if err != nil {
continue
}
t.lookupAccount(addr) t.lookupAccount(addr)
} }
} }

View file

@ -490,6 +490,7 @@ func (args *TransactionArgs) ToMessage(baseFee *big.Int, skipNonceCheck bool) *c
BlobGasFeeCap: (*big.Int)(args.BlobFeeCap), BlobGasFeeCap: (*big.Int)(args.BlobFeeCap),
BlobHashes: args.BlobHashes, BlobHashes: args.BlobHashes,
SetCodeAuthorizations: args.AuthorizationList, SetCodeAuthorizations: args.AuthorizationList,
AuthorityCache: types.ToAuthorityCache(args.AuthorizationList),
SkipNonceChecks: skipNonceCheck, SkipNonceChecks: skipNonceCheck,
SkipTransactionChecks: true, SkipTransactionChecks: true,
} }

View file

@ -477,6 +477,7 @@ func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (*core.Mess
BlobHashes: tx.BlobVersionedHashes, BlobHashes: tx.BlobVersionedHashes,
BlobGasFeeCap: tx.BlobGasFeeCap, BlobGasFeeCap: tx.BlobGasFeeCap,
SetCodeAuthorizations: authList, SetCodeAuthorizations: authList,
AuthorityCache: types.ToAuthorityCache(authList),
} }
return msg, nil return msg, nil
} }