Skip to content

Commit e8cff42

Browse files
committed
sync txpool update
1 parent 74b01b2 commit e8cff42

File tree

10 files changed

+341
-96
lines changed

10 files changed

+341
-96
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ test: all
4646
# EIP-7702 test
4747
cd ${PWD}/core/vm/runtime; go test -v -run=^TestDelegatedAccountAccessCost
4848
cd ${PWD}/core/types; go test -v -run=^TestParseDelegation
49+
cd ${PWD}/internal/ethapi; go test -v -run=^TestEstimateGas
4950

5051
lint: ## Run linters.
5152
$(GORUN) build/ci.go lint

core/blockchain_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3845,13 +3845,13 @@ func TestEIP7702(t *testing.T) {
38453845
blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 1, func(i int, b *BlockGen) {
38463846
b.SetCoinbase(aa)
38473847
txdata := &types.SetCodeTx{
3848-
ChainID: uint256.MustFromBig(gspec.Config.ChainID),
3849-
Nonce: 0,
3850-
To: addr1,
3851-
Gas: 500000,
3852-
GasFeeCap: uint256.MustFromBig(newGwei(5)),
3853-
GasTipCap: uint256.NewInt(2),
3854-
SetCodeAuthorizations: []types.SetCodeAuthorization{auth1, auth2},
3848+
ChainID: uint256.MustFromBig(gspec.Config.ChainID),
3849+
Nonce: 0,
3850+
To: addr1,
3851+
Gas: 500000,
3852+
GasFeeCap: uint256.MustFromBig(newGwei(5)),
3853+
GasTipCap: uint256.NewInt(2),
3854+
AuthList: []types.SetCodeAuthorization{auth1, auth2},
38553855
}
38563856
tx := types.MustSignNewTx(key1, signer, txdata)
38573857
b.AddTx(tx)

core/state_processor_test.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"golang.org/x/crypto/sha3"
2525

2626
"github.com/holiman/uint256"
27+
2728
"github.com/scroll-tech/go-ethereum/common"
2829
"github.com/scroll-tech/go-ethereum/common/math"
2930
"github.com/scroll-tech/go-ethereum/consensus"
@@ -97,14 +98,14 @@ func TestStateProcessorErrors(t *testing.T) {
9798
}
9899
var mkSetCodeTx = func(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, gasFeeCap *big.Int, setCodeAuthorizations []types.SetCodeAuthorization) *types.Transaction {
99100
tx, err := types.SignTx(types.NewTx(&types.SetCodeTx{
100-
ChainID: uint256.MustFromBig(config.ChainID),
101-
Nonce: nonce,
102-
GasTipCap: uint256.MustFromBig(gasTipCap),
103-
GasFeeCap: uint256.MustFromBig(gasFeeCap),
104-
Gas: gasLimit,
105-
To: to,
106-
Value: new(uint256.Int),
107-
SetCodeAuthorizations: setCodeAuthorizations,
101+
ChainID: uint256.MustFromBig(config.ChainID),
102+
Nonce: nonce,
103+
GasTipCap: uint256.MustFromBig(gasTipCap),
104+
GasFeeCap: uint256.MustFromBig(gasFeeCap),
105+
Gas: gasLimit,
106+
To: to,
107+
Value: new(uint256.Int),
108+
AuthList: setCodeAuthorizations,
108109
}), signer, key1)
109110
if err != nil {
110111
t.Fatal(err)

core/tx_pool.go

Lines changed: 59 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"github.com/scroll-tech/go-ethereum/core/rawdb"
3434
"github.com/scroll-tech/go-ethereum/core/state"
3535
"github.com/scroll-tech/go-ethereum/core/types"
36+
"github.com/scroll-tech/go-ethereum/crypto/codehash"
3637
"github.com/scroll-tech/go-ethereum/ethdb"
3738
"github.com/scroll-tech/go-ethereum/event"
3839
"github.com/scroll-tech/go-ethereum/log"
@@ -263,6 +264,20 @@ func (config *TxPoolConfig) sanitize() TxPoolConfig {
263264
// The pool separates processable transactions (which can be applied to the
264265
// current state) and future transactions. Transactions move between those
265266
// two states over time as they are received and processed.
267+
//
268+
// In addition to tracking transactions, the pool also tracks a set of pending SetCode
269+
// authorizations (EIP7702). This helps minimize number of transactions that can be
270+
// trivially churned in the pool. As a standard rule, any account with a deployed
271+
// delegation or an in-flight authorization to deploy a delegation will only be allowed a
272+
// single transaction slot instead of the standard number. This is due to the possibility
273+
// of the account being sweeped by an unrelated account.
274+
//
275+
// Because SetCode transactions can have many authorizations included, we avoid explicitly
276+
// checking their validity to save the state lookup. So long as the encompassing
277+
// transaction is valid, the authorization will be accepted and tracked by the pool. In
278+
// case the pool is tracking a pending / queued transaction from a specific account, it
279+
// will reject new transactions with delegations from that account with standard in-flight
280+
// transactions.
266281
type TxPool struct {
267282
config TxPoolConfig
268283
chainconfig *params.ChainConfig
@@ -789,41 +804,41 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
789804
if pool.currentState.GetBalance(from).Cmp(tx.Cost()) < 0 {
790805
return ErrInsufficientFunds
791806
}
792-
usedAndLeftSlots := func(addr common.Address) (int, int) {
793-
var have int
794-
if list := pool.pending[addr]; list != nil {
795-
have += list.Len()
796-
}
797-
if list := pool.queue[addr]; list != nil {
798-
have += list.Len()
799-
}
800-
if pool.currentState.GetCode(addr) != nil {
801-
// Allow at most one in-flight tx for delegated accounts.
802-
return have, max(0, 1-have)
803-
}
804-
return have, math.MaxInt
805-
}
806-
if used, left := usedAndLeftSlots(from); left <= 0 {
807-
return fmt.Errorf("%w: pooled %d txs", ErrAccountLimitExceeded, used)
808-
}
809-
knownConflicts := func(from common.Address, auths []common.Address) []common.Address {
810-
var conflicts []common.Address
811-
// The transaction sender cannot have an in-flight authorization.
812-
if _, ok := pool.all.auths[from]; ok {
813-
conflicts = append(conflicts, from)
814-
}
815-
// Authorities cannot conflict with any pending or queued transactions.
816-
for _, addr := range auths {
807+
list := pool.pending[from]
808+
if list == nil || !list.Overlaps(tx) {
809+
usedAndLeftSlots := func(addr common.Address) (int, int) {
810+
var have int
817811
if list := pool.pending[addr]; list != nil {
818-
conflicts = append(conflicts, addr)
819-
} else if list := pool.queue[addr]; list != nil {
820-
conflicts = append(conflicts, addr)
812+
have += list.Len()
821813
}
814+
if list := pool.queue[addr]; list != nil {
815+
have += list.Len()
816+
}
817+
if pool.currentState.GetKeccakCodeHash(addr) != codehash.EmptyKeccakCodeHash || len(pool.all.auths[addr]) != 0 {
818+
// Allow at most one in-flight tx for delegated accounts or those with
819+
// a pending authorization.
820+
return have, max(0, 1-have)
821+
}
822+
return have, math.MaxInt
823+
}
824+
if used, left := usedAndLeftSlots(from); left <= 0 {
825+
return fmt.Errorf("%w: pooled %d txs", ErrAccountLimitExceeded, used)
826+
}
827+
knownConflicts := func(auths []common.Address) []common.Address {
828+
var conflicts []common.Address
829+
// Authorities cannot conflict with any pending or queued transactions.
830+
for _, addr := range auths {
831+
if list := pool.pending[addr]; list != nil {
832+
conflicts = append(conflicts, addr)
833+
} else if list := pool.queue[addr]; list != nil {
834+
conflicts = append(conflicts, addr)
835+
}
836+
}
837+
return conflicts
838+
}
839+
if conflicts := knownConflicts(tx.SetCodeAuthorities()); len(conflicts) > 0 {
840+
return fmt.Errorf("%w: authorization conflicts with other known tx", ErrAuthorityReserved)
822841
}
823-
return conflicts
824-
}
825-
if conflicts := knownConflicts(from, tx.Authorities()); len(conflicts) > 0 {
826-
return fmt.Errorf("%w: authorization conflicts with other known tx", ErrAuthorityReserved)
827842
}
828843
if tx.Type() == types.SetCodeTxType {
829844
if len(tx.SetCodeAuthorizations()) == 0 {
@@ -2018,15 +2033,15 @@ type txLookup struct {
20182033
locals map[common.Hash]*types.Transaction
20192034
remotes map[common.Hash]*types.Transaction
20202035

2021-
auths map[common.Address][]*types.Transaction // All accounts with a pooled authorization
2036+
auths map[common.Address][]common.Hash // All accounts with a pooled authorization
20222037
}
20232038

20242039
// newTxLookup returns a new txLookup structure.
20252040
func newTxLookup() *txLookup {
20262041
return &txLookup{
20272042
locals: make(map[common.Hash]*types.Transaction),
20282043
remotes: make(map[common.Hash]*types.Transaction),
2029-
auths: make(map[common.Address][]*types.Transaction),
2044+
auths: make(map[common.Address][]common.Hash),
20302045
}
20312046
}
20322047

@@ -2133,6 +2148,7 @@ func (t *txLookup) Remove(hash common.Hash) {
21332148
t.lock.Lock()
21342149
defer t.lock.Unlock()
21352150

2151+
t.removeAuthorities(hash)
21362152
tx, ok := t.locals[hash]
21372153
if !ok {
21382154
tx, ok = t.remotes[hash]
@@ -2143,7 +2159,6 @@ func (t *txLookup) Remove(hash common.Hash) {
21432159
}
21442160
t.slots -= numSlots(tx)
21452161
slotsGauge.Update(int64(t.slots))
2146-
t.removeAuthorities(tx)
21472162

21482163
delete(t.locals, hash)
21492164
delete(t.remotes, hash)
@@ -2181,30 +2196,30 @@ func (t *txLookup) RemotesBelowTip(threshold *big.Int) types.Transactions {
21812196
// addAuthorities tracks the supplied tx in relation to each authority it
21822197
// specifies.
21832198
func (t *txLookup) addAuthorities(tx *types.Transaction) {
2184-
for _, addr := range tx.Authorities() {
2199+
for _, addr := range tx.SetCodeAuthorities() {
21852200
list, ok := t.auths[addr]
21862201
if !ok {
2187-
list = []*types.Transaction{}
2202+
list = []common.Hash{}
21882203
}
2189-
if slices.Contains(list, tx) {
2204+
if slices.Contains(list, tx.Hash()) {
21902205
// Don't add duplicates.
21912206
continue
21922207
}
2193-
list = append(list, tx)
2208+
list = append(list, tx.Hash())
21942209
t.auths[addr] = list
21952210
}
21962211
}
21972212

21982213
// removeAuthorities stops tracking the supplied tx in relation to its
21992214
// authorities.
2200-
func (t *txLookup) removeAuthorities(tx *types.Transaction) {
2201-
for _, addr := range tx.Authorities() {
2202-
// Remove tx from tracker.
2215+
func (t *txLookup) removeAuthorities(hash common.Hash) {
2216+
for addr := range t.auths {
22032217
list := t.auths[addr]
2204-
if i := slices.Index(list, tx); i >= 0 {
2218+
// Remove tx from tracker.
2219+
if i := slices.Index(list, hash); i >= 0 {
22052220
list = append(list[:i], list[i+1:]...)
22062221
} else {
2207-
log.Error("Authority with untracked tx", "addr", addr, "hash", tx.Hash())
2222+
log.Error("Authority with untracked tx", "addr", addr, "hash", hash)
22082223
}
22092224
if len(list) == 0 {
22102225
// If list is newly empty, delete it entirely.

0 commit comments

Comments
 (0)