Skip to content

Commit f343a9c

Browse files
jwasingerfjl
authored andcommitted
core/txpool, eth/catalyst: clear transaction pool in Rollback (#30534)
This adds an API method `DropTransactions` to legacy pool, blob pool and txpool interface. This method removes all txs currently tracked in the pools. It modifies the simulated beacon to use the new method in `Rollback` which removes previous hacky implementation that also erroneously reset the gas tip to 1 gwei. --------- Co-authored-by: Felix Lange <[email protected]>
1 parent e229c12 commit f343a9c

File tree

6 files changed

+108
-8
lines changed

6 files changed

+108
-8
lines changed

core/txpool/blobpool/blobpool.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1735,3 +1735,53 @@ func (p *BlobPool) Status(hash common.Hash) txpool.TxStatus {
17351735
}
17361736
return txpool.TxStatusUnknown
17371737
}
1738+
1739+
// Clear implements txpool.SubPool, removing all tracked transactions
1740+
// from the blob pool and persistent store.
1741+
func (p *BlobPool) Clear() {
1742+
p.lock.Lock()
1743+
defer p.lock.Unlock()
1744+
1745+
// manually iterating and deleting every entry is super sub-optimal
1746+
// However, Clear is not currently used in production so
1747+
// performance is not critical at the moment.
1748+
for hash := range p.lookup.txIndex {
1749+
id, _ := p.lookup.storeidOfTx(hash)
1750+
if err := p.store.Delete(id); err != nil {
1751+
log.Warn("failed to delete blob tx from backing store", "err", err)
1752+
}
1753+
}
1754+
for hash := range p.lookup.blobIndex {
1755+
id, _ := p.lookup.storeidOfBlob(hash)
1756+
if err := p.store.Delete(id); err != nil {
1757+
log.Warn("failed to delete blob from backing store", "err", err)
1758+
}
1759+
}
1760+
1761+
// unreserve each tracked account. Ideally, we could just clear the
1762+
// reservation map in the parent txpool context. However, if we clear in
1763+
// parent context, to avoid exposing the subpool lock, we have to lock the
1764+
// reservations and then lock each subpool.
1765+
//
1766+
// This creates the potential for a deadlock situation:
1767+
//
1768+
// * TxPool.Clear locks the reservations
1769+
// * a new transaction is received which locks the subpool mutex
1770+
// * TxPool.Clear attempts to lock subpool mutex
1771+
//
1772+
// The transaction addition may attempt to reserve the sender addr which
1773+
// can't happen until Clear releases the reservation lock. Clear cannot
1774+
// acquire the subpool lock until the transaction addition is completed.
1775+
for acct, _ := range p.index {
1776+
p.reserve(acct, false)
1777+
}
1778+
p.lookup = newLookup()
1779+
p.index = make(map[common.Address][]*blobTxMeta)
1780+
p.spent = make(map[common.Address]*uint256.Int)
1781+
1782+
var (
1783+
basefee = uint256.MustFromBig(eip1559.CalcBaseFee(p.chain.Config(), p.head))
1784+
blobfee = uint256.NewInt(params.BlobTxMinBlobGasprice)
1785+
)
1786+
p.evict = newPriceHeap(basefee, blobfee, p.index)
1787+
}

core/txpool/legacypool/cachepool.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,3 +892,9 @@ func (pool *CachePool) demoteUnexecutables() {
892892
}
893893
}
894894
}
895+
896+
// Clear implements txpool.SubPool
897+
//
898+
// For the cache pool, this method will do nothing for now.
899+
func (pool *CachePool) Clear() {
900+
}

core/txpool/legacypool/legacypool.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2090,3 +2090,44 @@ func (t *lookup) RemotesBelowTip(threshold *big.Int) types.Transactions {
20902090
func numSlots(tx *types.Transaction) int {
20912091
return int((tx.Size() + txSlotSize - 1) / txSlotSize)
20922092
}
2093+
2094+
// Clear implements txpool.SubPool, removing all tracked txs from the pool
2095+
// and rotating the journal.
2096+
func (pool *LegacyPool) Clear() {
2097+
pool.mu.Lock()
2098+
defer pool.mu.Unlock()
2099+
2100+
// unreserve each tracked account. Ideally, we could just clear the
2101+
// reservation map in the parent txpool context. However, if we clear in
2102+
// parent context, to avoid exposing the subpool lock, we have to lock the
2103+
// reservations and then lock each subpool.
2104+
//
2105+
// This creates the potential for a deadlock situation:
2106+
//
2107+
// * TxPool.Clear locks the reservations
2108+
// * a new transaction is received which locks the subpool mutex
2109+
// * TxPool.Clear attempts to lock subpool mutex
2110+
//
2111+
// The transaction addition may attempt to reserve the sender addr which
2112+
// can't happen until Clear releases the reservation lock. Clear cannot
2113+
// acquire the subpool lock until the transaction addition is completed.
2114+
for _, tx := range pool.all.remotes {
2115+
senderAddr, _ := types.Sender(pool.signer, tx)
2116+
pool.reserve(senderAddr, false)
2117+
}
2118+
for localSender, _ := range pool.locals.accounts {
2119+
pool.reserve(localSender, false)
2120+
}
2121+
2122+
pool.all = newLookup()
2123+
pool.priced = newPricedList(pool.all)
2124+
pool.pending = make(map[common.Address]*list)
2125+
pool.queue = make(map[common.Address]*list)
2126+
2127+
if !pool.config.NoLocals && pool.config.Journal != "" {
2128+
pool.journal = newTxJournal(pool.config.Journal)
2129+
if err := pool.journal.rotate(pool.local()); err != nil {
2130+
log.Warn("Failed to rotate transaction journal", "err", err)
2131+
}
2132+
}
2133+
}

core/txpool/subpool.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,9 @@ type SubPool interface {
180180
// identified by their hashes.
181181
Status(hash common.Hash) TxStatus
182182

183+
// Clear removes all tracked transactions from the pool
184+
Clear()
185+
183186
// GetCachedTransaction returns the encrypted transaction cached in tx pool.
184187
GetCachedTransaction(nonce uint64, sender common.Address) *types.Transaction
185188
}

core/txpool/txpool.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,3 +524,10 @@ func (p *TxPool) Sync() error {
524524
return errors.New("pool already terminated")
525525
}
526526
}
527+
528+
// Clear removes all tracked txs from the subpools.
529+
func (p *TxPool) Clear() {
530+
for _, subpool := range p.subpools {
531+
subpool.Clear()
532+
}
533+
}

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

@@ -287,12 +285,7 @@ func (c *SimulatedBeacon) Commit() common.Hash {
287285

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

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

0 commit comments

Comments
 (0)