Skip to content

Commit 7da8e27

Browse files
committed
core/txpool/blobpool: fix blob tx replacement
Signed-off-by: Csaba Kiraly <[email protected]>
1 parent d3a6bb7 commit 7da8e27

File tree

1 file changed

+42
-24
lines changed

1 file changed

+42
-24
lines changed

core/txpool/blobpool/blobpool.go

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,6 +1741,13 @@ func (p *BlobPool) add(tx *types.Transaction) (err error) {
17411741
addtimeHist.Update(time.Since(start).Nanoseconds())
17421742
}(time.Now())
17431743

1744+
return p.addLocked(tx, true)
1745+
}
1746+
1747+
// addLocked inserts a new blob transaction into the pool if it passes validation (both
1748+
// consensus validity and pool restrictions). It must be called with the pool lock held.
1749+
// Only for internal use.
1750+
func (p *BlobPool) addLocked(tx *types.Transaction, checkGapped bool) (err error) {
17441751
// Ensure the transaction is valid from all perspectives
17451752
if err := p.validateTx(tx); err != nil {
17461753
log.Trace("Transaction validation failed", "hash", tx.Hash(), "err", err)
@@ -1904,34 +1911,48 @@ func (p *BlobPool) add(tx *types.Transaction) (err error) {
19041911

19051912
addValidMeter.Mark(1)
19061913

1914+
// Notify all listeners of the new arrival
1915+
p.discoverFeed.Send(core.NewTxsEvent{Txs: []*types.Transaction{tx.WithoutBlobTxSidecar()}})
1916+
p.insertFeed.Send(core.NewTxsEvent{Txs: []*types.Transaction{tx.WithoutBlobTxSidecar()}})
1917+
19071918
//check the gapped queue for this account and try to promote
1908-
if gtxs, ok := p.gapped[from]; ok && len(gtxs) > 0 {
1919+
if gtxs, ok := p.gapped[from]; checkGapped && ok && len(gtxs) > 0 {
19091920
// We have to add in nonce order, but we want to stable sort to cater for situations
19101921
// where transactions are replaced, keeping the original receive order for same nonce
19111922
sort.SliceStable(gtxs, func(i, j int) bool {
19121923
return gtxs[i].tx.Nonce() < gtxs[j].tx.Nonce()
19131924
})
1914-
firstgap := p.state.GetNonce(from) + uint64(len(p.index[from]))
19151925
for len(gtxs) > 0 {
1916-
if gtxs[0].tx.Nonce() <= firstgap {
1917-
// Drop any buffered transactions that became stale in themeantime (included in chain or replaced)
1918-
// If we arrive to the tx at the first gap, we try to add it now (also dropping it from the gapped queue)
1919-
tx := gtxs[0].tx
1920-
gtxs[0] = nil
1921-
gtxs = gtxs[1:]
1922-
delete(p.gappedSource, tx.Hash())
1923-
if tx.Nonce() == firstgap {
1924-
// We are under lock. Add the first transaction in a goroutine to avoid blocking.
1925-
// This might lead to a race between new calls to add and the revalidation here,
1926-
// we should revisit if this is a potential issue.
1927-
go func() {
1928-
if err := p.add(tx); err == nil {
1929-
log.Trace("Gapped blob transaction added to pool", "hash", tx.Hash(), "from", from, "nonce", tx.Nonce(), "qlen", len(p.gapped[from]))
1930-
} else {
1931-
log.Trace("Gapped blob transaction not accepted", "hash", tx.Hash(), "from", from, "nonce", tx.Nonce(), "err", err)
1932-
}
1933-
}()
1934-
break
1926+
stateNonce := p.state.GetNonce(from)
1927+
firstgap := stateNonce + uint64(len(p.index[from]))
1928+
1929+
if gtxs[0].tx.Nonce() > firstgap {
1930+
// Anything beyond the first gap is not addable yet
1931+
break
1932+
}
1933+
1934+
// Drop any buffered transactions that became stale in the meantime (included in chain or replaced)
1935+
// If we arrive to the transaction in the pending range (between the state Nonce and first gap, we
1936+
// try to add them now while removing from here.
1937+
tx := gtxs[0].tx
1938+
gtxs[0] = nil
1939+
gtxs = gtxs[1:]
1940+
delete(p.gappedSource, tx.Hash())
1941+
1942+
if tx.Nonce() < stateNonce {
1943+
// Stale, drop it. Eventually we could add to limbo here if hash matches.
1944+
log.Trace("Gapped blob transaction became stale", "hash", tx.Hash(), "from", from, "nonce", tx.Nonce(), "state", stateNonce, "qlen", len(p.gapped[from]))
1945+
continue
1946+
}
1947+
1948+
if tx.Nonce() <= firstgap {
1949+
// If we hit the pending range, including the first gap, add it and continue to try to add more.
1950+
// We do not recurse here, but continue to loop instead.
1951+
// We are under lock, so we can add the transaction directly.
1952+
if err := p.addLocked(tx, false); err == nil {
1953+
log.Trace("Gapped blob transaction added to pool", "hash", tx.Hash(), "from", from, "nonce", tx.Nonce(), "qlen", len(p.gapped[from]))
1954+
} else {
1955+
log.Trace("Gapped blob transaction not accepted", "hash", tx.Hash(), "from", from, "nonce", tx.Nonce(), "err", err)
19351956
}
19361957
}
19371958
}
@@ -1941,9 +1962,6 @@ func (p *BlobPool) add(tx *types.Transaction) (err error) {
19411962
p.gapped[from] = gtxs
19421963
}
19431964
}
1944-
// Notify all listeners of the new arrival
1945-
p.discoverFeed.Send(core.NewTxsEvent{Txs: []*types.Transaction{tx.WithoutBlobTxSidecar()}})
1946-
p.insertFeed.Send(core.NewTxsEvent{Txs: []*types.Transaction{tx.WithoutBlobTxSidecar()}})
19471965
return nil
19481966
}
19491967

0 commit comments

Comments
 (0)