diff --git a/eth/fetcher/tx_fetcher.go b/eth/fetcher/tx_fetcher.go index a11b5e2164..95fef0cdee 100644 --- a/eth/fetcher/tx_fetcher.go +++ b/eth/fetcher/tx_fetcher.go @@ -24,8 +24,8 @@ import ( "sort" "time" + mapset "github.com/deckarep/golang-set/v2" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" @@ -53,9 +53,6 @@ const ( // re-request them. maxTxUnderpricedSetSize = 32768 - // maxTxUnderpricedTimeout is the max time a transaction should be stuck in the underpriced set. - maxTxUnderpricedTimeout = int64(5 * time.Minute) - // txArriveTimeout is the time allowance before an announced transaction is // explicitly requested. txArriveTimeout = 500 * time.Millisecond @@ -151,7 +148,7 @@ type TxFetcher struct { drop chan *txDrop quit chan struct{} - underpriced *lru.Cache[common.Hash, int64] // Transactions discarded as too cheap (don't re-fetch) + underpriced mapset.Set[common.Hash] // Transactions discarded as too cheap (don't re-fetch) // Stage 1: Waiting lists for newly discovered transactions that might be // broadcast without needing explicit request/reply round trips. @@ -205,7 +202,7 @@ func NewTxFetcherForTests( fetching: make(map[common.Hash]string), requests: make(map[string]*txRequest), alternates: make(map[common.Hash]map[string]struct{}), - underpriced: lru.NewCache[common.Hash, int64](maxTxUnderpricedSetSize), + underpriced: mapset.NewSet[common.Hash](), hasTx: hasTx, addTxs: addTxs, fetchTxs: fetchTxs, @@ -226,16 +223,17 @@ func (f *TxFetcher) Notify(peer string, hashes []common.Hash) error { // still valuable to check here because it runs concurrent to the internal // loop, so anything caught here is time saved internally. var ( - unknowns = make([]common.Hash, 0, len(hashes)) - duplicate int64 - underpriced int64 + unknowns = make([]common.Hash, 0, len(hashes)) + duplicate, underpriced int64 ) for _, hash := range hashes { switch { case f.hasTx(hash): duplicate++ - case f.isKnownUnderpriced(hash): + + case f.underpriced.Contains(hash): underpriced++ + default: unknowns = append(unknowns, hash) } @@ -247,7 +245,10 @@ func (f *TxFetcher) Notify(peer string, hashes []common.Hash) error { if len(unknowns) == 0 { return nil } - announce := &txAnnounce{origin: peer, hashes: unknowns} + announce := &txAnnounce{ + origin: peer, + hashes: unknowns, + } select { case f.notify <- announce: return nil @@ -256,16 +257,6 @@ func (f *TxFetcher) Notify(peer string, hashes []common.Hash) error { } } -// isKnownUnderpriced reports whether a transaction hash was recently found to be underpriced. -func (f *TxFetcher) isKnownUnderpriced(hash common.Hash) bool { - prevTime, ok := f.underpriced.Peek(hash) - if ok && prevTime+maxTxUnderpricedTimeout < time.Now().Unix() { - f.underpriced.Remove(hash) - return false - } - return ok -} - // Enqueue imports a batch of received transaction into the transaction pool // and the fetcher. This method may be called by both transaction broadcasts and // direct request replies. The differentiation is important so the fetcher can @@ -309,7 +300,10 @@ func (f *TxFetcher) Enqueue(peer string, txs []*types.Transaction, direct bool) // Avoid re-request this transaction when we receive another // announcement. if errors.Is(err, txpool.ErrUnderpriced) || errors.Is(err, txpool.ErrReplaceUnderpriced) { - f.underpriced.Add(batch[j].Hash(), batch[j].Time().Unix()) + for f.underpriced.Cardinality() >= maxTxUnderpricedSetSize { + f.underpriced.Pop() + } + f.underpriced.Add(batch[j].Hash()) } // Track a few interesting failure types switch { diff --git a/eth/fetcher/tx_fetcher_test.go b/eth/fetcher/tx_fetcher_test.go index 980c1a6c26..1715def99c 100644 --- a/eth/fetcher/tx_fetcher_test.go +++ b/eth/fetcher/tx_fetcher_test.go @@ -1509,8 +1509,8 @@ func testTransactionFetcher(t *testing.T, tt txFetcherTest) { } case isUnderpriced: - if fetcher.underpriced.Len() != int(step) { - t.Errorf("step %d: underpriced set size mismatch: have %d, want %d", i, fetcher.underpriced.Len(), step) + if fetcher.underpriced.Cardinality() != int(step) { + t.Errorf("step %d: underpriced set size mismatch: have %d, want %d", i, fetcher.underpriced.Cardinality(), step) } default: