From 9726ecf6309bbfebc4ebefe1b51730d62fedf727 Mon Sep 17 00:00:00 2001 From: Mayveskii Date: Mon, 11 May 2026 18:46:06 +0300 Subject: [PATCH] core/txpool/blobpool: fix update() index corruption dropStore deletes l.index[txhash] which already points to newID after setAndIndex succeeds. Instead, inline the cleanup: delete store slot and groups entry only, leaving the index mapping intact. This matches the pattern used in finalize() and addLocked() replacement path where store Delete is done without touching the index. --- core/txpool/blobpool/limbo.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/core/txpool/blobpool/limbo.go b/core/txpool/blobpool/limbo.go index 15004ca4f9..b17338a7f0 100644 --- a/core/txpool/blobpool/limbo.go +++ b/core/txpool/blobpool/limbo.go @@ -215,9 +215,16 @@ func (l *limbo) update(txhash common.Hash, block uint64) { return } // New entry created successfully, now drop the old one. - if err := l.dropStore(oldID, item); err != nil { + // Do not use dropStore here - it deletes l.index[txhash] which + // already points to newID after setAndIndex. Only clean store + // and groups entries, leaving the index mapping intact. + if err := l.store.Delete(oldID); err != nil { log.Error("failed to drop old limboed blob slot", "id", oldID, "err", err) } + delete(l.groups[item.Block], oldID) + if len(l.groups[item.Block]) == 0 { + delete(l.groups, item.Block) + } log.Trace("Blob transaction updated in limbo", "tx", txhash, "old-block", item.Block, "new-block", block) } @@ -235,8 +242,8 @@ func (l *limbo) peek(id uint64) (*limboBlob, error) { return item, nil } -// dropStore deletes a blob item from the store and indices. -// Used by update to remove the old entry after successful setAndIndex. +// dropStore deletes a blob item from the store and in-memory indices. +// Used by getAndDrop/pull for full removal of a limbo entry. func (l *limbo) dropStore(id uint64, item *limboBlob) error { if err := l.store.Delete(id); err != nil { return err