core/txpool/blobpool: fix reorder buffer logic

Signed-off-by: Csaba Kiraly <csaba.kiraly@gmail.com>
This commit is contained in:
Csaba Kiraly 2025-09-24 17:36:52 +02:00
parent 0e5ae8e438
commit 66eae3c0db
No known key found for this signature in database
GPG key ID: 0FE274EE8C95166E

View file

@ -1909,34 +1909,44 @@ func (p *BlobPool) add(tx *types.Transaction) (err error) {
addValidMeter.Mark(1) addValidMeter.Mark(1)
//check the gapped queue for this account and try to add any pending transactions //check the gapped queue for this account and try to promote
if gtxs, ok := p.gapped[from]; ok && len(gtxs) > 0 { if gtxs, ok := p.gapped[from]; ok && len(gtxs) > 0 {
// We have to add in nonce order, but we want to stable sort to cater for situations // We have to add in nonce order, but we want to stable sort to cater for situations
// where transactions are replaced // where transactions are replaced, keeping the original receive order for same nonce
sort.SliceStable(gtxs, func(i, j int) bool { sort.SliceStable(gtxs, func(i, j int) bool {
return gtxs[i].tx.Nonce() < gtxs[j].tx.Nonce() return gtxs[i].tx.Nonce() < gtxs[j].tx.Nonce()
}) })
firstgap := p.state.GetNonce(from) + uint64(len(p.index[from])) firstgap := p.state.GetNonce(from) + uint64(len(p.index[from]))
tx := gtxs[0].tx for len(gtxs) > 0 {
log.Trace("Gapped blob transactions found", "from", from, "qlen", len(gtxs), "firstNonceGap", firstgap, "nonce0", tx.Nonce()) if gtxs[0].tx.Nonce() <= firstgap {
if firstgap == tx.Nonce() { // Drop any buffered transactions that became stale in themeantime (included in chain or replaced)
// We are under lock. Add the first transaction in a goroutine to avoid blocking. // If we arrive to the tx at the first gap, we try to add it now (also dropping it from the gapped queue)
// This might lead to a race beteen new calls to add and the revalidation here, tx := gtxs[0].tx
// TODO: revisit if this is a problem, lock on 'from' needed? gtxs[0] = nil
p.gapped[from] = gtxs[1:] gtxs = gtxs[1:]
if len(p.gapped[from]) == 0 { delete(p.gappedSource, tx.Hash())
delete(p.gapped, from) if tx.Nonce() == firstgap {
} // We are under lock. Add the first transaction in a goroutine to avoid blocking.
delete(p.gappedSource, tx.Hash()) // This might lead to a race beteen new calls to add and the revalidation here,
go func() { // we should revisit if this is a potential issue.
if err := p.add(tx); err == nil { go func() {
log.Trace("Gapped blob transaction added to pool", "hash", tx.Hash(), "from", from, "nonce", tx.Nonce(), "qlen", len(p.gapped[from])) if err := p.add(tx); err == nil {
} else { log.Trace("Gapped blob transaction added to pool", "hash", tx.Hash(), "from", from, "nonce", tx.Nonce(), "qlen", len(p.gapped[from]))
log.Trace("Gapped blob transaction still not accepted", "hash", tx.Hash(), "from", from, "nonce", tx.Nonce(), "err", err) } else {
log.Trace("Gapped blob transaction not accepted", "hash", tx.Hash(), "from", from, "nonce", tx.Nonce(), "err", err)
}
}()
break
} }
}() }
}
if len(gtxs) == 0 {
delete(p.gapped, from)
} else {
p.gapped[from] = gtxs
} }
} }
// Notify all listeners of the new arrival
p.discoverFeed.Send(core.NewTxsEvent{Txs: []*types.Transaction{tx.WithoutBlobTxSidecar()}}) p.discoverFeed.Send(core.NewTxsEvent{Txs: []*types.Transaction{tx.WithoutBlobTxSidecar()}})
p.insertFeed.Send(core.NewTxsEvent{Txs: []*types.Transaction{tx.WithoutBlobTxSidecar()}}) p.insertFeed.Send(core.NewTxsEvent{Txs: []*types.Transaction{tx.WithoutBlobTxSidecar()}})
return nil return nil