Skip to content

Commit bb9897f

Browse files
authored
core/txpool, eth/catalyst: ensure gas tip retains current value upon rollback (#30495)
Here we move the method that drops all transactions by temporarily increasing the fee into the TxPool itself. It's better to have it there because we can set it back to the configured value afterwards. This resolves a TODO in the simulated backend.
1 parent 93675d1 commit bb9897f

File tree

5 files changed

+86
-61
lines changed

5 files changed

+86
-61
lines changed

core/txpool/blobpool/blobpool.go

Lines changed: 58 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,56 @@ func (p *BlobPool) reinject(addr common.Address, txhash common.Hash) error {
10131013
return nil
10141014
}
10151015

1016+
func (p *BlobPool) flushTransactionsBelowTip(tip *uint256.Int) {
1017+
for addr, txs := range p.index {
1018+
for i, tx := range txs {
1019+
if tx.execTipCap.Cmp(tip) < 0 {
1020+
// Drop the offending transaction
1021+
var (
1022+
ids = []uint64{tx.id}
1023+
nonces = []uint64{tx.nonce}
1024+
)
1025+
p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], txs[i].costCap)
1026+
p.stored -= uint64(tx.size)
1027+
delete(p.lookup, tx.hash)
1028+
txs[i] = nil
1029+
1030+
// Drop everything afterwards, no gaps allowed
1031+
for j, tx := range txs[i+1:] {
1032+
ids = append(ids, tx.id)
1033+
nonces = append(nonces, tx.nonce)
1034+
1035+
p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], tx.costCap)
1036+
p.stored -= uint64(tx.size)
1037+
delete(p.lookup, tx.hash)
1038+
txs[i+1+j] = nil
1039+
}
1040+
// Clear out the dropped transactions from the index
1041+
if i > 0 {
1042+
p.index[addr] = txs[:i]
1043+
heap.Fix(p.evict, p.evict.index[addr])
1044+
} else {
1045+
delete(p.index, addr)
1046+
delete(p.spent, addr)
1047+
1048+
heap.Remove(p.evict, p.evict.index[addr])
1049+
p.reserve(addr, false)
1050+
}
1051+
// Clear out the transactions from the data store
1052+
log.Warn("Dropping underpriced blob transaction", "from", addr, "rejected", tx.nonce, "tip", tx.execTipCap, "want", tip, "drop", nonces, "ids", ids)
1053+
dropUnderpricedMeter.Mark(int64(len(ids)))
1054+
1055+
for _, id := range ids {
1056+
if err := p.store.Delete(id); err != nil {
1057+
log.Error("Failed to delete dropped transaction", "id", id, "err", err)
1058+
}
1059+
}
1060+
break
1061+
}
1062+
}
1063+
}
1064+
}
1065+
10161066
// SetGasTip implements txpool.SubPool, allowing the blob pool's gas requirements
10171067
// to be kept in sync with the main transaction pool's gas requirements.
10181068
func (p *BlobPool) SetGasTip(tip *big.Int) {
@@ -1025,59 +1075,20 @@ func (p *BlobPool) SetGasTip(tip *big.Int) {
10251075

10261076
// If the min miner fee increased, remove transactions below the new threshold
10271077
if old == nil || p.gasTip.Cmp(old) > 0 {
1028-
for addr, txs := range p.index {
1029-
for i, tx := range txs {
1030-
if tx.execTipCap.Cmp(p.gasTip) < 0 {
1031-
// Drop the offending transaction
1032-
var (
1033-
ids = []uint64{tx.id}
1034-
nonces = []uint64{tx.nonce}
1035-
)
1036-
p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], txs[i].costCap)
1037-
p.stored -= uint64(tx.size)
1038-
delete(p.lookup, tx.hash)
1039-
txs[i] = nil
1040-
1041-
// Drop everything afterwards, no gaps allowed
1042-
for j, tx := range txs[i+1:] {
1043-
ids = append(ids, tx.id)
1044-
nonces = append(nonces, tx.nonce)
1045-
1046-
p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], tx.costCap)
1047-
p.stored -= uint64(tx.size)
1048-
delete(p.lookup, tx.hash)
1049-
txs[i+1+j] = nil
1050-
}
1051-
// Clear out the dropped transactions from the index
1052-
if i > 0 {
1053-
p.index[addr] = txs[:i]
1054-
heap.Fix(p.evict, p.evict.index[addr])
1055-
} else {
1056-
delete(p.index, addr)
1057-
delete(p.spent, addr)
1058-
1059-
heap.Remove(p.evict, p.evict.index[addr])
1060-
p.reserve(addr, false)
1061-
}
1062-
// Clear out the transactions from the data store
1063-
log.Warn("Dropping underpriced blob transaction", "from", addr, "rejected", tx.nonce, "tip", tx.execTipCap, "want", tip, "drop", nonces, "ids", ids)
1064-
dropUnderpricedMeter.Mark(int64(len(ids)))
1065-
1066-
for _, id := range ids {
1067-
if err := p.store.Delete(id); err != nil {
1068-
log.Error("Failed to delete dropped transaction", "id", id, "err", err)
1069-
}
1070-
}
1071-
break
1072-
}
1073-
}
1074-
}
1078+
p.flushTransactionsBelowTip(p.gasTip)
10751079
}
10761080
log.Debug("Blobpool tip threshold updated", "tip", tip)
10771081
pooltipGauge.Update(tip.Int64())
10781082
p.updateStorageMetrics()
10791083
}
10801084

1085+
func (p *BlobPool) FlushAllTransactions() {
1086+
maxUint256 := uint256.MustFromBig(new(big.Int).Sub(new(big.Int).Lsh(common.Big1, 256), common.Big1))
1087+
p.lock.Lock()
1088+
defer p.lock.Unlock()
1089+
p.flushTransactionsBelowTip(maxUint256)
1090+
}
1091+
10811092
// validateTx checks whether a transaction is valid according to the consensus
10821093
// rules and adheres to some heuristic limits of the local node (price and size).
10831094
func (p *BlobPool) validateTx(tx *types.Transaction) error {

core/txpool/legacypool/legacypool.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,15 @@ func (pool *LegacyPool) SubscribeTransactions(ch chan<- core.NewTxsEvent, reorgs
429429
return pool.txFeed.Subscribe(ch)
430430
}
431431

432+
func (pool *LegacyPool) flushTransactionsBelowTip(tip *big.Int) {
433+
// pool.priced is sorted by GasFeeCap, so we have to iterate through pool.all instead
434+
drop := pool.all.RemotesBelowTip(tip)
435+
for _, tx := range drop {
436+
pool.removeTx(tx.Hash(), false, true)
437+
}
438+
pool.priced.Removed(len(drop))
439+
}
440+
432441
// SetGasTip updates the minimum gas tip required by the transaction pool for a
433442
// new transaction, and drops all transactions below this threshold.
434443
func (pool *LegacyPool) SetGasTip(tip *big.Int) {
@@ -442,16 +451,18 @@ func (pool *LegacyPool) SetGasTip(tip *big.Int) {
442451
pool.gasTip.Store(newTip)
443452
// If the min miner fee increased, remove transactions below the new threshold
444453
if newTip.Cmp(old) > 0 {
445-
// pool.priced is sorted by GasFeeCap, so we have to iterate through pool.all instead
446-
drop := pool.all.RemotesBelowTip(tip)
447-
for _, tx := range drop {
448-
pool.removeTx(tx.Hash(), false, true)
449-
}
450-
pool.priced.Removed(len(drop))
454+
pool.flushTransactionsBelowTip(tip)
451455
}
452456
log.Info("Legacy pool tip threshold updated", "tip", newTip)
453457
}
454458

459+
func (pool *LegacyPool) FlushAllTransactions() {
460+
maxUint256 := new(big.Int).Sub(new(big.Int).Lsh(common.Big1, 256), common.Big1)
461+
pool.mu.Lock()
462+
defer pool.mu.Unlock()
463+
pool.flushTransactionsBelowTip(maxUint256)
464+
}
465+
455466
// Nonce returns the next nonce of an account, with all transactions executable
456467
// by the pool already applied on top.
457468
func (pool *LegacyPool) Nonce(addr common.Address) uint64 {

core/txpool/subpool.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ type SubPool interface {
116116
// transaction, and drops all transactions below this threshold.
117117
SetGasTip(tip *big.Int)
118118

119+
// FlushAllTransactions drops all transactions in the pool.
120+
FlushAllTransactions()
121+
119122
// Has returns an indicator whether subpool has a transaction cached with the
120123
// given hash.
121124
Has(hash common.Hash) bool

core/txpool/txpool.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,13 @@ func New(gasTip uint64, chain BlockChain, subpools []SubPool) (*TxPool, error) {
104104
return pool, nil
105105
}
106106

107+
// FlushAllTransactions removes all transactions from all subpools
108+
func (p *TxPool) FlushAllTransactions() {
109+
for _, subpool := range p.subpools {
110+
subpool.FlushAllTransactions()
111+
}
112+
}
113+
107114
// reserver is a method to create an address reservation callback to exclusively
108115
// assign/deassign addresses to/from subpools. This can ensure that at any point
109116
// in time, only a single subpool is able to manage an account, avoiding cross

eth/catalyst/simulated_beacon.go

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121
"crypto/sha256"
2222
"errors"
2323
"fmt"
24-
"math/big"
2524
"sync"
2625
"time"
2726

@@ -34,7 +33,6 @@ import (
3433
"github.com/ethereum/go-ethereum/event"
3534
"github.com/ethereum/go-ethereum/log"
3635
"github.com/ethereum/go-ethereum/node"
37-
"github.com/ethereum/go-ethereum/params"
3836
"github.com/ethereum/go-ethereum/rpc"
3937
)
4038

@@ -286,12 +284,7 @@ func (c *SimulatedBeacon) Commit() common.Hash {
286284

287285
// Rollback un-sends previously added transactions.
288286
func (c *SimulatedBeacon) Rollback() {
289-
// Flush all transactions from the transaction pools
290-
maxUint256 := new(big.Int).Sub(new(big.Int).Lsh(common.Big1, 256), common.Big1)
291-
c.eth.TxPool().SetGasTip(maxUint256)
292-
// Set the gas tip back to accept new transactions
293-
// TODO (Marius van der Wijden): set gas tip to parameter passed by config
294-
c.eth.TxPool().SetGasTip(big.NewInt(params.GWei))
287+
c.eth.TxPool().FlushAllTransactions()
295288
}
296289

297290
// Fork sets the head to the provided hash.

0 commit comments

Comments
 (0)