eth/fetcher: don't spend too much time on transaction inclusion (#25524)

* eth/fetcher: introduce some lag in tx fetching

* eth/fetcher: change conditions a bit

* eth/fetcher: use per-batch quota check

* eth/fetcher: fix some comments

* eth/fetcher: address review concerns

* eth/fetcher: fix panic + add warn log

* eth/fetcher: fix log

* eth/fetcher: fix log

* cmd/devp2p/internal/ethtest: fix ignorign tx announcements from prev. tests

* cmd/devp2p/internal/ethtest: fix TestLargeTxRequest

This increases the number of tx relay messages the test waits for. Since
go-ethereum now processes incoming txs in smaller batches, the
announcement messages it sends are also smaller.

Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
Martin Holst Swende
2022-08-19 16:59:36 +03:00
committed by GitHub
co-authored by Felix Lange
parent ac7ad811b4
commit 0ce494b60c
4 changed files with 73 additions and 43 deletions
+61 -39
View File
@@ -262,57 +262,79 @@ func (f *TxFetcher) Notify(peer string, hashes []common.Hash) error {
// direct request replies. The differentiation is important so the fetcher can
// re-schedule missing transactions as soon as possible.
func (f *TxFetcher) Enqueue(peer string, txs []*types.Transaction, direct bool) error {
// Keep track of all the propagated transactions
if direct {
txReplyInMeter.Mark(int64(len(txs)))
} else {
txBroadcastInMeter.Mark(int64(len(txs)))
var (
inMeter = txReplyInMeter
knownMeter = txReplyKnownMeter
underpricedMeter = txReplyUnderpricedMeter
otherRejectMeter = txReplyOtherRejectMeter
)
if !direct {
inMeter = txBroadcastInMeter
knownMeter = txBroadcastKnownMeter
underpricedMeter = txBroadcastUnderpricedMeter
otherRejectMeter = txBroadcastOtherRejectMeter
}
// Keep track of all the propagated transactions
inMeter.Mark(int64(len(txs)))
// Push all the transactions into the pool, tracking underpriced ones to avoid
// re-requesting them and dropping the peer in case of malicious transfers.
var (
added = make([]common.Hash, 0, len(txs))
duplicate int64
underpriced int64
otherreject int64
added = make([]common.Hash, 0, len(txs))
delay time.Duration
)
errs := f.addTxs(txs)
for i, err := range errs {
// Track the transaction hash if the price is too low for us.
// Avoid re-request this transaction when we receive another
// announcement.
if errors.Is(err, core.ErrUnderpriced) || errors.Is(err, core.ErrReplaceUnderpriced) {
for f.underpriced.Cardinality() >= maxTxUnderpricedSetSize {
f.underpriced.Pop()
// proceed in batches
for i := 0; i < len(txs); i += 128 {
end := i + 128
if end > len(txs) {
end = len(txs)
}
var (
duplicate int64
underpriced int64
otherreject int64
)
batch := txs[i:end]
for j, err := range f.addTxs(batch) {
// Track the transaction hash if the price is too low for us.
// Avoid re-request this transaction when we receive another
// announcement.
if errors.Is(err, core.ErrUnderpriced) || errors.Is(err, core.ErrReplaceUnderpriced) {
for f.underpriced.Cardinality() >= maxTxUnderpricedSetSize {
f.underpriced.Pop()
}
f.underpriced.Add(batch[j].Hash())
}
f.underpriced.Add(txs[i].Hash())
// Track a few interesting failure types
switch {
case err == nil: // Noop, but need to handle to not count these
case errors.Is(err, core.ErrAlreadyKnown):
duplicate++
case errors.Is(err, core.ErrUnderpriced) || errors.Is(err, core.ErrReplaceUnderpriced):
underpriced++
default:
otherreject++
}
added = append(added, batch[j].Hash())
}
// Track a few interesting failure types
switch {
case err == nil: // Noop, but need to handle to not count these
knownMeter.Mark(duplicate)
underpricedMeter.Mark(underpriced)
otherRejectMeter.Mark(otherreject)
case errors.Is(err, core.ErrAlreadyKnown):
duplicate++
case errors.Is(err, core.ErrUnderpriced) || errors.Is(err, core.ErrReplaceUnderpriced):
underpriced++
default:
otherreject++
// If 'other reject' is >25% of the deliveries in any batch, abort. Either we are
// out of sync with the chain or the peer is griefing us.
if otherreject > 128/4 {
delay = 200 * time.Millisecond
log.Warn("Peer delivering useless transactions", "peer", peer, "ignored", len(txs)-end)
break
}
added = append(added, txs[i].Hash())
}
if direct {
txReplyKnownMeter.Mark(duplicate)
txReplyUnderpricedMeter.Mark(underpriced)
txReplyOtherRejectMeter.Mark(otherreject)
} else {
txBroadcastKnownMeter.Mark(duplicate)
txBroadcastUnderpricedMeter.Mark(underpriced)
txBroadcastOtherRejectMeter.Mark(otherreject)
}
select {
case f.cleanup <- &txDelivery{origin: peer, hashes: added, direct: direct}:
time.Sleep(delay)
return nil
case <-f.quit:
return errTerminated