core/txpool/blobpool: fall back to pool in GetCells for blob-mode cache entries (#35439)
Some checks are pending
/ Linux Build (push) Waiting to run
/ Linux Build (arm) (push) Waiting to run
/ Keeper Build (push) Waiting to run
/ Windows Build (push) Waiting to run
/ Docker Image (push) Waiting to run

## Description

Blob mode cache entries (the default until a CL advertises
`engine_getBlobsV4` via `engine_exchangeCapabilities`) carry no cells,
but `Cache.GetCells` treated any entry as a hit and served null cells
from the empty custody set instead of falling back to the pool.

Found via the EELS execute-blobs simulator (EIP-8070 `engine_getBlobsV4`
tests), which never calls `engine_exchangeCapabilities`: null cells
appeared intermittently depending on the race with the 1s top-K preload.
With the fix the suite passes 139/139 (from 87/139 on master).
This commit is contained in:
spencer 2026-07-30 17:39:50 +02:00 committed by GitHub
parent b988c00bf4
commit 7a1b11564c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 34 additions and 1 deletions

View file

@ -265,7 +265,10 @@ func (c *Cache) GetCells(vhashes []common.Hash, mask types.CustodyBitmap) ([][]*
c.mu.Lock()
for vhash, idxs := range indices {
cached, ok := c.entries[vhash]
if !ok {
if !ok || cached.cell == nil {
// Entries loaded in blob mode carry no cells; fall back to
// the blobpool instead of serving null cells for a blob
// that is actually available.
misses = append(misses, vhash)
continue
}

View file

@ -283,6 +283,36 @@ func TestCacheGetBlobs(t *testing.T) {
tc.expectEntries(t, tc.vhashes[1]...)
}
// TestCacheGetCellsBlobModeFallback checks that GetCells falls back to the
// blobpool for entries that were cached in blob mode (without cells) instead
// of serving null cells for a blob that is available in the pool.
func TestCacheGetCellsBlobModeFallback(t *testing.T) {
tc := newTestCache(t, []txSpec{
{blobs: 1, tip: 300},
})
tc.expectEntries(t, tc.vhashes[0]...) // blob-mode entries, no cells
cells, proofs, err := tc.GetCells(tc.vhashes[0], types.CustodyBitmapAll)
if err != nil {
t.Fatalf("GetCells: %v", err)
}
for i := range cells {
if len(cells[i]) == 0 {
t.Errorf("no cells returned for blob %d", i)
}
for j, cell := range cells[i] {
if cell == nil {
t.Errorf("cell %d of blob %d missing in GetCells response", j, i)
}
}
for j, proof := range proofs[i] {
if proof == nil {
t.Errorf("proof %d of blob %d missing in GetCells response", j, i)
}
}
}
}
// TestCacheTopKRefresh verifies that when a more profitable tx appears in the
// pool, the next topK tick replaces the cached entry with the better one.
func TestCacheTopKRefresh(t *testing.T) {