mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-10 00:41:35 +00:00
core: rework tx auth cache
This commit is contained in:
parent
95c732cfac
commit
df0f945f6d
6 changed files with 57 additions and 86 deletions
|
|
@ -156,7 +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
|
Authorities []*common.Address // Recovered authority addresses
|
||||||
|
|
||||||
// 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.
|
||||||
|
|
@ -186,7 +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(),
|
Authorities: tx.SetCodeAuthorities(),
|
||||||
SkipNonceChecks: false,
|
SkipNonceChecks: false,
|
||||||
SkipTransactionChecks: false,
|
SkipTransactionChecks: false,
|
||||||
BlobHashes: tx.BlobHashes(),
|
BlobHashes: tx.BlobHashes(),
|
||||||
|
|
@ -507,12 +507,12 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
||||||
// Apply EIP-7702 authorizations.
|
// Apply EIP-7702 authorizations.
|
||||||
if msg.SetCodeAuthorizations != nil {
|
if msg.SetCodeAuthorizations != nil {
|
||||||
for i, auth := range msg.SetCodeAuthorizations {
|
for i, auth := range msg.SetCodeAuthorizations {
|
||||||
// Note errors are ignored, we simply skip invalid authorizations here.
|
addr := msg.Authorities[i]
|
||||||
authority, err := msg.AuthorityCache.Authority(i)
|
if addr == nil {
|
||||||
if err != nil {
|
// Skip invalid authorizations.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
st.applyAuthorization(&auth, authority)
|
st.applyAuthorization(&auth, *addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -580,18 +580,16 @@ 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, preDerivedAuthority common.Address) (authority common.Address, err error) {
|
func (st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorization, authority common.Address) 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 ErrAuthorizationWrongChainID
|
||||||
}
|
}
|
||||||
// Limit nonce to 2^64-1 per EIP-2681.
|
// Limit nonce to 2^64-1 per EIP-2681.
|
||||||
if auth.Nonce+1 < auth.Nonce {
|
if auth.Nonce+1 < auth.Nonce {
|
||||||
return authority, ErrAuthorizationNonceOverflow
|
return ErrAuthorizationNonceOverflow
|
||||||
}
|
}
|
||||||
|
|
||||||
authority = preDerivedAuthority
|
|
||||||
|
|
||||||
// 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
|
||||||
|
|
@ -600,17 +598,17 @@ func (st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorizatio
|
||||||
st.state.AddAddressToAccessList(authority)
|
st.state.AddAddressToAccessList(authority)
|
||||||
code := st.state.GetCode(authority)
|
code := st.state.GetCode(authority)
|
||||||
if _, ok := types.ParseDelegation(code); len(code) != 0 && !ok {
|
if _, ok := types.ParseDelegation(code); len(code) != 0 && !ok {
|
||||||
return authority, ErrAuthorizationDestinationHasCode
|
return ErrAuthorizationDestinationHasCode
|
||||||
}
|
}
|
||||||
if have := st.state.GetNonce(authority); have != auth.Nonce {
|
if have := st.state.GetNonce(authority); have != auth.Nonce {
|
||||||
return authority, ErrAuthorizationNonceMismatch
|
return ErrAuthorizationNonceMismatch
|
||||||
}
|
}
|
||||||
return authority, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, preDerivedAuthority common.Address) error {
|
func (st *stateTransition) applyAuthorization(auth *types.SetCodeAuthorization, authority common.Address) error {
|
||||||
authority, err := st.validateAuthorization(auth, preDerivedAuthority)
|
err := st.validateAuthorization(auth, authority)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -619,7 +619,7 @@ func (pool *LegacyPool) validateAuth(tx *types.Transaction) error {
|
||||||
}
|
}
|
||||||
// For symmetry, allow at most one in-flight tx for any authority with a
|
// For symmetry, allow at most one in-flight tx for any authority with a
|
||||||
// pending transaction.
|
// pending transaction.
|
||||||
if auths := tx.SetCodeAuthorities(); len(auths) > 0 {
|
if auths := tx.UniqueSetCodeAuthorities(); len(auths) > 0 {
|
||||||
for _, auth := range auths {
|
for _, auth := range auths {
|
||||||
var count int
|
var count int
|
||||||
if pending := pool.pending[auth]; pending != nil {
|
if pending := pool.pending[auth]; pending != nil {
|
||||||
|
|
@ -1748,7 +1748,7 @@ func (t *lookup) TxsBelowTip(threshold *big.Int) types.Transactions {
|
||||||
// addAuthorities tracks the supplied tx in relation to each authority it
|
// addAuthorities tracks the supplied tx in relation to each authority it
|
||||||
// specifies.
|
// specifies.
|
||||||
func (t *lookup) addAuthorities(tx *types.Transaction) {
|
func (t *lookup) addAuthorities(tx *types.Transaction) {
|
||||||
for _, addr := range tx.SetCodeAuthorities() {
|
for _, addr := range tx.UniqueSetCodeAuthorities() {
|
||||||
list, ok := t.auths[addr]
|
list, ok := t.auths[addr]
|
||||||
if !ok {
|
if !ok {
|
||||||
list = []common.Hash{}
|
list = []common.Hash{}
|
||||||
|
|
@ -1766,7 +1766,7 @@ func (t *lookup) addAuthorities(tx *types.Transaction) {
|
||||||
// authorities.
|
// authorities.
|
||||||
func (t *lookup) removeAuthorities(tx *types.Transaction) {
|
func (t *lookup) removeAuthorities(tx *types.Transaction) {
|
||||||
hash := tx.Hash()
|
hash := tx.Hash()
|
||||||
for _, addr := range tx.SetCodeAuthorities() {
|
for _, addr := range tx.UniqueSetCodeAuthorities() {
|
||||||
list := t.auths[addr]
|
list := t.auths[addr]
|
||||||
// Remove tx from tracker.
|
// Remove tx from tracker.
|
||||||
if i := slices.Index(list, hash); i >= 0 {
|
if i := slices.Index(list, hash); i >= 0 {
|
||||||
|
|
|
||||||
|
|
@ -273,7 +273,7 @@ func validatePoolInternals(pool *LegacyPool) error {
|
||||||
}
|
}
|
||||||
// Ensure all auths in pool are tracked
|
// Ensure all auths in pool are tracked
|
||||||
for _, tx := range pool.all.txs {
|
for _, tx := range pool.all.txs {
|
||||||
for _, addr := range tx.SetCodeAuthorities() {
|
for _, addr := range tx.UniqueSetCodeAuthorities() {
|
||||||
list := pool.all.auths[addr]
|
list := pool.all.auths[addr]
|
||||||
if i := slices.Index(list, tx.Hash()); i < 0 {
|
if i := slices.Index(list, tx.Hash()); i < 0 {
|
||||||
return fmt.Errorf("authority not tracked: addr %s, tx %s", addr, tx.Hash())
|
return fmt.Errorf("authority not tracked: addr %s, tx %s", addr, tx.Hash())
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,10 @@ type Transaction struct {
|
||||||
time time.Time // Time first seen locally (spam avoidance)
|
time time.Time // Time first seen locally (spam avoidance)
|
||||||
|
|
||||||
// caches
|
// caches
|
||||||
hash atomic.Pointer[common.Hash]
|
hash atomic.Pointer[common.Hash]
|
||||||
size atomic.Uint64
|
size atomic.Uint64
|
||||||
from atomic.Pointer[sigCache]
|
from atomic.Pointer[sigCache]
|
||||||
|
auths atomic.Pointer[authCache]
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTx creates a new transaction.
|
// NewTx creates a new transaction.
|
||||||
|
|
@ -512,32 +513,36 @@ func (tx *Transaction) SetCodeAuthorizations() []SetCodeAuthorization {
|
||||||
return setcodetx.AuthList
|
return setcodetx.AuthList
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCodeAuthorities returns a list of unique authorities from the
|
// SetCodeAuthorities returns a list of authorities from the authorization list.
|
||||||
// authorization list.
|
// Nil is used to represent authorizations that fail derivation.
|
||||||
func (tx *Transaction) SetCodeAuthorities() []common.Address {
|
func (tx *Transaction) SetCodeAuthorities() []*common.Address {
|
||||||
setcodetx, ok := tx.inner.(*SetCodeTx)
|
setcodetx, ok := tx.inner.(*SetCodeTx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if authorityCache := setcodetx.authorityCache.Load(); authorityCache != nil {
|
if cache := tx.auths.Load(); cache != nil {
|
||||||
return authorityCache.authorities
|
return *cache
|
||||||
}
|
}
|
||||||
cache := ToAuthorityCache(setcodetx.AuthList)
|
cache := setcodetx.deriveAuthorities()
|
||||||
setcodetx.authorityCache.Store(cache)
|
tx.auths.Store(&cache)
|
||||||
return cache.authorities
|
return cache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *Transaction) AuthorityCache() *AuthorityCache {
|
// UniqueSetCodeAuthorities returns a list of unique authorities from the
|
||||||
setcodetx, ok := tx.inner.(*SetCodeTx)
|
// authorization list.
|
||||||
if !ok {
|
func (tx *Transaction) UniqueSetCodeAuthorities() []common.Address {
|
||||||
return nil
|
var (
|
||||||
|
auths = tx.SetCodeAuthorities()
|
||||||
|
marks = make(map[common.Address]bool)
|
||||||
|
uniques []common.Address
|
||||||
|
)
|
||||||
|
for _, auth := range auths {
|
||||||
|
if auth != nil && !marks[*auth] {
|
||||||
|
marks[*auth] = true
|
||||||
|
uniques = append(uniques, *auth)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if authorityCache := setcodetx.authorityCache.Load(); authorityCache != nil {
|
return uniques
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -67,56 +67,24 @@ type SetCodeTx struct {
|
||||||
S *uint256.Int
|
S *uint256.Int
|
||||||
|
|
||||||
// caches
|
// caches
|
||||||
authorityCache atomic.Pointer[AuthorityCache]
|
auths atomic.Pointer[authCache]
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToAuthorityCache(authList []SetCodeAuthorization) *AuthorityCache {
|
type authCache []*common.Address
|
||||||
var (
|
|
||||||
marks = make(map[common.Address]bool)
|
// deriveAuthorities returns a list of recovered authorization signers. The
|
||||||
auths = make([]common.Address, 0, len(authList))
|
// length is always equal to the number of authorizations. Any authorities that
|
||||||
invalid []invalidAuth // empty since it's expected to be empty most of the time
|
// fail to recover are set as nil in the list.
|
||||||
)
|
func (tx *SetCodeTx) deriveAuthorities() authCache {
|
||||||
for i, auth := range authList {
|
auths := make([]*common.Address, 0, len(tx.AuthList))
|
||||||
|
for _, auth := range tx.AuthList {
|
||||||
if addr, err := auth.Authority(); err == nil {
|
if addr, err := auth.Authority(); err == nil {
|
||||||
if marks[addr] {
|
auths = append(auths, &addr)
|
||||||
continue
|
|
||||||
}
|
|
||||||
marks[addr] = true
|
|
||||||
auths = append(auths, addr)
|
|
||||||
} else {
|
} else {
|
||||||
invalid = append(invalid, invalidAuth{index: i, error: err})
|
auths = append(auths, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &AuthorityCache{authorities: auths, invalidAuths: invalid}
|
return auths
|
||||||
}
|
|
||||||
|
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -185,7 +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 _, addr := range tx.SetCodeAuthorities() {
|
for _, addr := range tx.UniqueSetCodeAuthorities() {
|
||||||
t.lookupAccount(addr)
|
t.lookupAccount(addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue