fix: Check L1DataFee in txpool promoteExecutables and demoteUnexecutables (#948)

fix: Check L1DataFee in txpool promoteExecutables and demoteUnexecutables (#627)

* Check L1DataFee in txpool promoteExecutables

* bump version

* implement L1 data fee in demoteUnexecutables as well

* Update core/tx_list.go



* Update core/tx_pool.go



* 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: vyzo <vyzo@hackzen.org>
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>
This commit is contained in:
HAOYUatHZ 2024-08-02 14:54:13 +08:00 committed by GitHub
parent 15e380d0dd
commit 58ed1a2a3b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 56 additions and 2 deletions

View file

@ -1500,8 +1500,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)
@ -1549,6 +1551,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.
@ -1702,7 +1724,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)

View file

@ -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 {