erigontech / erigontech/erigon

cl/das: Gloas blob recovery stores recovered columns under slot 0

Open
#22,806 1 comment 0 reactions 1 assignee Claimed by @domiwei View on GitHub
Caplin Glamsterdam type:bug
Dominant language
Go
Stars
3.6k
Forks
1.5k
Avg merge
1d 16h
Merged PRs (30d)
455

Description

## Problem

On the Gloas path, blob recovery reconstructs the custody columns it is missing and writes them under **slot 0** instead of the block's real slot, making them invisible to every later lookup.

In `cl/das/peer_das.go` (the `!exist` branch of the recovery loop, around lines 528-543):

```go
sidecar := cltypes.NewDataColumnSidecar() // version stays at the zero value: phase0
sidecar.Index = columnIndex
sidecar.SignedBlockHeader = anyColumnSidecar.SignedBlockHeader // nil under the Gloas schema
if !isGloas {
sidecar.KzgCommitmentsInclusionProof = anyColumnSidecar.KzgCommitmentsInclusionProof
sidecar.KzgCommitments = anyColumnSidecar.KzgCommitments
}
```

`NewDataColumnSidecar()` leaves the internal `version` at its zero value, `phase0`, rather than the fork the sidecar actually belongs to. On the Gloas path `anyColumnSidecar.SignedBlockHeader` is nil, and `Slot` / `BeaconBlockRoot` are never assigned.

`WriteColumnSidecars` (`cl/persistence/blob_storage/data_column_db.go:69-89`) then derives the slot as: Gloas version → `columnData.Slot`; else non-nil header → header slot; else → `columnData.Slot`. With version `phase0` and a nil header it falls through to the last branch, so `slot = 0`.

## Effect

- The reconstructed columns land at `0/_` and are invisible to `GetSavedColumnIndex(realSlot, blockRoot)`, so the node believes it still lacks its custody columns.
- They are also encoded with the pre-Gloas schema, because `getSchemaForVersion` re-initializes an empty `SignedBlockHeader` and commitments for a sub-Gloas version.
- `Prune` is keyed on slot, so these files sit in the slot-0 subdirectory rather than with the block they belong to.

Confirmed with a throwaway test: `NewDataColumnSidecar().Version()` reports `phase0`, and the write lands at `0/0x0100…00_7`.

## Scope

Requires `GloasForkEpoch` to be scheduled, so devnets rather than mainnet today. It is a mis-filing rather than a crash, and it is not peer-controlled — the input is locally reconstructed data.

## Suggestion

Construct the sidecar with the fork it belongs to and populate the fields that schema requires, e.g. `cltypes.NewDataColumnSidecarWithVersion(anyColumnSidecar.Version())`, then set `Slot` and `BeaconBlockRoot` on the Gloas path. More generally, `NewDataColumnSidecar()` defaulting to `phase0` is an easy footgun for any caller that later relies on `Version()`.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.