Thu, Jun 4, 2026 Latest

Blob inclusion

Analysis of blob inclusion patterns in Ethereum mainnet blocks.

Blobs included per slot

Each dot represents a slot, colored by the number of blobs included (0–9). This shows the temporal distribution of blob activity—gaps indicate missed slots or blocks without blobs.

View query
SELECT
    s.slot AS slot,
    s.slot_start_date_time AS time,
    COALESCE(b.blob_count, 0) AS blob_count
FROM (
    SELECT DISTINCT slot, slot_start_date_time
    FROM default.canonical_beacon_block
    WHERE meta_network_name = 'mainnet'
      AND slot_start_date_time >= '2026-06-04' AND slot_start_date_time < '2026-06-04'::date + INTERVAL 1 DAY
) s
LEFT JOIN (
    SELECT
        slot,
        COUNT(*) AS blob_count
    FROM default.canonical_beacon_blob_sidecar
    WHERE meta_network_name = 'mainnet'
      AND slot_start_date_time >= '2026-06-04' AND slot_start_date_time < '2026-06-04'::date + INTERVAL 1 DAY
    GROUP BY slot
) b ON s.slot = b.slot
ORDER BY s.slot ASC
Show code
df_blobs_per_slot = load_parquet("blobs_per_slot", target_date)

fig = px.scatter(
    df_blobs_per_slot,
    x="time",
    y="blob_count",
    color="blob_count",
    color_continuous_scale="YlOrRd",
    labels={"time": "Time", "blob_count": "Blob Count", "slot": "Slot"},
    template="plotly",
    hover_data={"slot": True, "time": True, "blob_count": True},
)
fig.update_traces(
    marker=dict(size=3),
    hovertemplate="<b>Slot:</b> %{customdata[0]}<br><b>Time:</b> %{x}<br><b>Blob Count:</b> %{y}<extra></extra>",
)
fig.update_layout(
    margin=dict(l=60, r=30, t=30, b=60),
    autosize=True,
    showlegend=False,
    yaxis=dict(dtick=1, range=[-0.5, 15.5], title=dict(standoff=10)),
    xaxis=dict(title=dict(standoff=15)),
    coloraxis_colorbar=dict(title=dict(text="Blobs", side="right")),
    height=600,
)
fig.show(config={"responsive": True})

Blob count breakdown per epoch

Stacked bar chart showing how blocks within each epoch are distributed by blob count. Each bar represents one epoch (32 slots), with colors indicating the number of blobs in each block.

View query
WITH blob_counts_per_slot AS (
    SELECT
        slot,
        epoch,
        epoch_start_date_time,
        slot_start_date_time,
        toUInt64(max(blob_index) + 1) as blob_count
    FROM canonical_beacon_blob_sidecar
    WHERE meta_network_name = 'mainnet'
      AND slot_start_date_time >= '2026-06-04' AND slot_start_date_time < '2026-06-04'::date + INTERVAL 1 DAY
    GROUP BY slot, epoch, epoch_start_date_time, slot_start_date_time
),
blocks_per_epoch AS (
    SELECT
        epoch,
        epoch_start_date_time,
        toUInt64(COUNT(DISTINCT slot)) as total_blocks
    FROM canonical_beacon_block
    WHERE meta_network_name = 'mainnet'
      AND slot_start_date_time >= '2026-06-04' AND slot_start_date_time < '2026-06-04'::date + INTERVAL 1 DAY
    GROUP BY epoch, epoch_start_date_time
),
epochs AS (
    SELECT DISTINCT epoch, epoch_start_date_time
    FROM blocks_per_epoch
),
all_blob_counts AS (
    SELECT arrayJoin(range(toUInt64(0), toUInt64(max(blob_count) + 1))) AS blob_count
    FROM blob_counts_per_slot
),
all_combinations AS (
    SELECT
        e.epoch,
        e.epoch_start_date_time,
        b.blob_count
    FROM epochs e
    CROSS JOIN all_blob_counts b
),
block_per_blob_count_per_epoch AS (
    SELECT
        epoch,
        epoch_start_date_time,
        blob_count,
        toUInt64(COUNT(*)) as block_count
    FROM blob_counts_per_slot
    GROUP BY epoch, epoch_start_date_time, blob_count
),
blocks_with_blobs_per_epoch AS (
    SELECT
        epoch,
        toUInt64(COUNT(*)) as blocks_with_blobs
    FROM blob_counts_per_slot
    GROUP BY epoch
)
SELECT
    a.epoch AS epoch,
    a.epoch_start_date_time AS time,
    a.blob_count AS blob_count,
    CASE
        WHEN a.blob_count = 0 THEN
            toInt64(COALESCE(blk.total_blocks, toUInt64(0))) - toInt64(COALESCE(wb.blocks_with_blobs, toUInt64(0)))
        ELSE
            toInt64(COALESCE(b.block_count, toUInt64(0)))
    END as block_count
FROM all_combinations a
GLOBAL LEFT JOIN block_per_blob_count_per_epoch b
    ON a.epoch = b.epoch AND a.blob_count = b.blob_count
GLOBAL LEFT JOIN blocks_per_epoch blk
    ON a.epoch = blk.epoch
GLOBAL LEFT JOIN blocks_with_blobs_per_epoch wb
    ON a.epoch = wb.epoch
ORDER BY a.epoch ASC, a.blob_count ASC
Show code
df_blocks_blob_epoch = load_parquet("blocks_blob_epoch", target_date)

# Format blob count as "XX blobs" for display (moved from SQL for cleaner queries)
df_blocks_blob_epoch["series"] = df_blocks_blob_epoch["blob_count"].apply(lambda x: f"{int(x):02d} blobs")

chart = (
    alt.Chart(df_blocks_blob_epoch)
    .mark_bar()
    .encode(
        x=alt.X("time:T"),
        y=alt.Y("block_count:Q", stack="zero", scale=alt.Scale(domain=[0, 32]), axis=alt.Axis(tickCount=32, labelAngle=-45)),
        color=alt.Color(
            "series:N",
            sort="ascending",
            scale=alt.Scale(scheme="inferno"),
        ),
        order=alt.Order("series:N", sort="ascending"),
        tooltip=[
            alt.Tooltip("time:T", title="Epoch Time"),
            alt.Tooltip("epoch:Q", title="Epoch"),
            alt.Tooltip("series:N", title="Blob Count"),
            alt.Tooltip("block_count:Q", title="Block Count"),
        ],
    )
    .properties(height=600, width=800)
)
chart