Skip to content

Commit

Permalink
fix: Check L1DataFee in txpool promoteExecutables and demoteUnexecuta…
Browse files Browse the repository at this point in the history
…bles (#627)

* Check L1DataFee in txpool promoteExecutables

* bump version

* implement L1 data fee in demoteUnexecutables as well

* Update core/tx_list.go

Co-authored-by: colin <102356659+colinlyguo@users.noreply.github.com>

* Update core/tx_pool.go

Co-authored-by: Péter Garamvölgyi <peter@scroll.io>

* feat: consider l1 data fee in txpool costcap (#681)

* feat(txpool): consider l1 data fee in costcap

* fix CI

* simplify logic

* remove one db read op

* bump version

---------

Co-authored-by: colin <102356659+colinlyguo@users.noreply.github.com>
Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
Co-authored-by: georgehao <haohongfan@gmail.com>
  • Loading branch information
4 people authored and HAOYUatHZ committed Aug 1, 2024
1 parent 17acae8 commit a3fee98
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 2 deletions.
27 changes: 25 additions & 2 deletions core/txpool/legacypool/legacypool.go
Original file line number Diff line number Diff line change
Expand Up @@ -1466,8 +1466,10 @@ func (pool *LegacyPool) promoteExecutables(accounts []common.Address) []*types.T
pool.all.Remove(hash)
}
log.Trace("Removed old queued transactions", "count", len(forwards))

// Drop all transactions that are too costly (low balance or out of gas)
drops, _ := list.Filter(pool.currentState.GetBalance(addr), gasLimit)
costLimit := pool.currentState.GetBalance(addr)
drops, _ := list.FilterF(costLimit, gasLimit, pool.executableTxFilter(costLimit, gasLimit))
for _, tx := range drops {
hash := tx.Hash()
pool.all.Remove(hash)
Expand Down Expand Up @@ -1515,6 +1517,26 @@ func (pool *LegacyPool) promoteExecutables(accounts []common.Address) []*types.T
return promoted
}

func (pool *LegacyPool) executableTxFilter(costLimit *big.Int, gasLimit uint64) func(tx *types.Transaction) bool {
return func(tx *types.Transaction) bool {
if tx.Gas() > gasLimit || tx.Cost().Cmp(costLimit) > 0 {
return true
}

if pool.chainconfig.Scroll.FeeVaultEnabled() {
// recheck L1 data fee, as the oracle price may have changed
l1DataFee, err := fees.CalculateL1DataFee(tx, pool.currentState, pool.chainconfig, pool.currentHead.Load().Number)
if err != nil {
log.Error("Failed to calculate L1 data fee", "err", err, "tx", tx)
return false
}
return costLimit.Cmp(new(big.Int).Add(tx.Cost(), l1DataFee)) < 0
}

return false
}
}

// truncatePending removes transactions from the pending queue if the pool is above the
// pending limit. The algorithm tries to reduce transaction counts by an approximately
// equal number for all for accounts with many pending transactions.
Expand Down Expand Up @@ -1668,7 +1690,8 @@ func (pool *LegacyPool) demoteUnexecutables() {
log.Trace("Removed old pending transaction", "hash", hash)
}
// Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later
drops, invalids := list.Filter(pool.currentState.GetBalance(addr), gasLimit)
costLimit := pool.currentState.GetBalance(addr)
drops, invalids := list.FilterF(costLimit, gasLimit, pool.executableTxFilter(costLimit, gasLimit))
for _, tx := range drops {
hash := tx.Hash()
log.Trace("Removed unpayable pending transaction", "hash", hash)
Expand Down
31 changes: 31 additions & 0 deletions core/txpool/legacypool/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,37 @@ func (l *list) Filter(costLimit *big.Int, gasLimit uint64) (types.Transactions,
return removed, invalids
}

// FilterF removes all transactions from the list that satisfy a predicate.
// Every removed transaction is returned for any post-removal maintenance.
// Strict-mode invalidated transactions are also returned.
func (l *list) FilterF(costLimit *big.Int, gasLimit uint64, f func(tx *types.Transaction) bool) (types.Transactions, types.Transactions) {
// If all transactions are below the threshold, short circuit
if l.costcap.Cmp(costLimit) <= 0 && l.gascap <= gasLimit {
return nil, nil
}
l.costcap = new(big.Int).Set(costLimit) // Lower the caps to the thresholds
l.gascap = gasLimit

removed := l.txs.Filter(f)

if len(removed) == 0 {
return nil, nil
}
var invalids types.Transactions
// If the list was strict, filter anything above the lowest nonce
if l.strict {
lowest := uint64(math.MaxUint64)
for _, tx := range removed {
if nonce := tx.Nonce(); lowest > nonce {
lowest = nonce
}
}
invalids = l.txs.filter(func(tx *types.Transaction) bool { return tx.Nonce() > lowest })
}
l.txs.reheap()
return removed, invalids
}

// Cap places a hard limit on the number of items, returning all transactions
// exceeding that limit.
func (l *list) Cap(threshold int) types.Transactions {
Expand Down

0 comments on commit a3fee98

Please sign in to comment.