Skip to content

Commit e007e7b

Browse files
authored
refactor: removing blob index (#19204)
## Summary Removed the `index` field from blob-related data structures (`BlobJson`, `BlobWithIndex`, `BlobsWithIndexes`) since it was unreliable across different blob sources and completely unused by production code. ## Motivation The blob `index` field was problematic for several reasons: ### 1. Inconsistent values across sources | Source | Index Value | Issue | |--------|-------------|-------| | L1 Beacon API | Correct (0, 1, 2...) | Only reliable source | | FileStore | Always `-1` | By design - filestores don't track original indices | | Blobscan Archive | Re-indexed (0, 1, 2...) | Incorrect - returns indices relative to each API response, not the original block indices | ### 2. Production code never used the index The archiver's blob retrieval immediately discarded the index by mapping to just the blob data before processing. ### 3. The `indices` parameter was never used The `getBlobSidecar()` method had an optional `indices` parameter that was never called with actual values. ### 4. `BlobsWithIndexes.getBlobsFromIndices` was buggy The method used array position instead of the blob's actual index field for filtering, making it fundamentally broken. ## Changes - Removed `index: string` from `BlobJson` interface - Deleted `BlobWithIndex` and `BlobsWithIndexes` classes - Updated all client interfaces to return `Blob[]` directly - Removed unused `indices` parameter from `getBlobSidecar()` - Updated tests
2 parents 04a0538 + 69ab75e commit e007e7b

File tree

21 files changed

+152
-398
lines changed

21 files changed

+152
-398
lines changed

yarn-project/archiver/src/archiver/archiver.test.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type { BlobClientInterface } from '@aztec/blob-client/client';
2-
import { BlobWithIndex } from '@aztec/blob-client/types';
3-
import { getBlobsPerL1Block, getPrefixedEthBlobCommitments } from '@aztec/blob-lib';
2+
import { type Blob, getBlobsPerL1Block, getPrefixedEthBlobCommitments } from '@aztec/blob-lib';
43
import { makeRandomBlob } from '@aztec/blob-lib/testing';
54
import { GENESIS_ARCHIVE_ROOT } from '@aztec/constants';
65
import type { EpochCache, EpochCommitteeInfo } from '@aztec/epoch-cache';
@@ -199,7 +198,7 @@ describe('Archiver', () => {
199198
// REFACTOR: we should have a single method that creates all these artifacts, as well as the l2 proposed event
200199
let allRollupTxs: Map<`0x${string}`, Transaction>;
201200
let allVersionedBlobHashes: Map<`0x${string}`, `0x${string}`[]>;
202-
let allBlobs: Map<`0x${string}`, BlobWithIndex[]>;
201+
let allBlobs: Map<`0x${string}`, Blob[]>;
203202

204203
let logger: Logger;
205204

@@ -1207,8 +1206,8 @@ describe('Archiver', () => {
12071206

12081207
mockRollup.read.status.mockResolvedValue([0n, GENESIS_ROOT, 1n, checkpoint.archive.root.toString(), GENESIS_ROOT]);
12091208

1210-
const randomBlob = new BlobWithIndex(makeRandomBlob(3), 0);
1211-
const randomBlobHash = randomBlob.blob.getEthVersionedBlobHash();
1209+
const randomBlob = makeRandomBlob(3);
1210+
const randomBlobHash = randomBlob.getEthVersionedBlobHash();
12121211

12131212
makeCheckpointProposedEvent(70n, checkpoint.number, checkpoint.archive.root.toString(), [
12141213
`0x${randomBlobHash.toString()}`,
@@ -2023,7 +2022,7 @@ describe('Archiver', () => {
20232022
*/
20242023
const makeBlobsFromCheckpoint = (checkpoint: Checkpoint) => {
20252024
const blobFields = checkpoint.toBlobFields();
2026-
const blobs = getBlobsPerL1Block(blobFields).map((blob, index) => new BlobWithIndex(blob, index));
2025+
const blobs = getBlobsPerL1Block(blobFields);
20272026
allBlobs.set(checkpoint.archive.root.toString(), blobs);
20282027
return blobs;
20292028
};

yarn-project/archiver/src/archiver/l1/data_retrieval.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,15 +331,15 @@ export async function getCheckpointBlobDataFromBlobs(
331331
logger: Logger,
332332
isHistoricalSync: boolean,
333333
): Promise<CheckpointBlobData> {
334-
const blobBodies = await blobClient.getBlobSidecar(blockHash, blobHashes, undefined, { isHistoricalSync });
334+
const blobBodies = await blobClient.getBlobSidecar(blockHash, blobHashes, { isHistoricalSync });
335335
if (blobBodies.length === 0) {
336336
throw new NoBlobBodiesFoundError(checkpointNumber);
337337
}
338338

339339
let checkpointBlobData: CheckpointBlobData;
340340
try {
341341
// Attempt to decode the checkpoint blob data.
342-
checkpointBlobData = decodeCheckpointBlobDataFromBlobs(blobBodies.map(b => b.blob));
342+
checkpointBlobData = decodeCheckpointBlobDataFromBlobs(blobBodies);
343343
} catch (err: any) {
344344
if (err instanceof BlobDeserializationError) {
345345
logger.fatal(err.message);

yarn-project/blob-client/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
"./client": "./dest/client/index.js",
88
"./client/config": "./dest/client/config.js",
99
"./encoding": "./dest/encoding/index.js",
10-
"./types": "./dest/types/index.js",
1110
"./filestore": "./dest/filestore/index.js"
1211
},
1312
"inherits": [

yarn-project/blob-client/src/archive/blobscan_archive_client.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,20 @@ export const BlobscanBlockResponseSchema = zodFor<BlobJson[]>()(
2525
commitment: z.string(),
2626
proof: z.string(),
2727
size: z.number().int(),
28-
index: z.number().int().optional(), // This is the index within the tx, not within the block!
28+
index: z.number().int().optional(), // Unused, kept for schema compatibility with blobscan API
2929
}),
3030
),
3131
}),
3232
),
3333
})
3434
.transform(data =>
35-
data.transactions
36-
.flatMap(tx =>
37-
tx.blobs.map(blob => ({
38-
blob: blob.data,
39-
// eslint-disable-next-line camelcase
40-
kzg_commitment: blob.commitment,
41-
})),
42-
)
43-
.map((blob, index) => ({ ...blob, index: index.toString() })),
35+
data.transactions.flatMap(tx =>
36+
tx.blobs.map(blob => ({
37+
blob: blob.data,
38+
// eslint-disable-next-line camelcase
39+
kzg_commitment: blob.commitment,
40+
})),
41+
),
4442
),
4543
);
4644

Lines changed: 15 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { Blob } from '@aztec/blob-lib';
22
import { Fr } from '@aztec/foundation/curves/bn254';
33

4-
import { BlobWithIndex } from '../types/index.js';
54
import type { BlobStore } from './interface.js';
65

76
export function describeBlobStore(getBlobStore: () => Promise<BlobStore>) {
@@ -15,39 +14,36 @@ export function describeBlobStore(getBlobStore: () => Promise<BlobStore>) {
1514
// Create a test blob with random fields
1615
const testFields = [Fr.random(), Fr.random(), Fr.random()];
1716
const blob = Blob.fromFields(testFields);
18-
const blobWithIndex = new BlobWithIndex(blob, 0);
1917
const blobHash = blob.getEthVersionedBlobHash();
2018

2119
// Store the blob
22-
await blobStore.addBlobs([blobWithIndex]);
20+
await blobStore.addBlobs([blob]);
2321

2422
// Retrieve the blob by hash
2523
const retrievedBlobs = await blobStore.getBlobsByHashes([blobHash]);
2624

2725
// Verify the blob was retrieved and matches
2826
expect(retrievedBlobs.length).toBe(1);
29-
expect(retrievedBlobs[0].blob).toEqual(blob);
27+
expect(retrievedBlobs[0]).toEqual(blob);
3028
});
3129

3230
it('should handle multiple blobs stored and retrieved by their hashes', async () => {
3331
// Create two different blobs
3432
const blob1 = Blob.fromFields([Fr.random(), Fr.random()]);
3533
const blob2 = Blob.fromFields([Fr.random(), Fr.random(), Fr.random()]);
36-
const blobWithIndex1 = new BlobWithIndex(blob1, 0);
37-
const blobWithIndex2 = new BlobWithIndex(blob2, 1);
3834

3935
const blobHash1 = blob1.getEthVersionedBlobHash();
4036
const blobHash2 = blob2.getEthVersionedBlobHash();
4137

4238
// Store both blobs
43-
await blobStore.addBlobs([blobWithIndex1, blobWithIndex2]);
39+
await blobStore.addBlobs([blob1, blob2]);
4440

4541
// Retrieve and verify both blobs
4642
const retrievedBlobs = await blobStore.getBlobsByHashes([blobHash1, blobHash2]);
4743

4844
expect(retrievedBlobs.length).toBe(2);
49-
expect(retrievedBlobs[0].blob).toEqual(blob1);
50-
expect(retrievedBlobs[1].blob).toEqual(blob2);
45+
expect(retrievedBlobs[0]).toEqual(blob1);
46+
expect(retrievedBlobs[1]).toEqual(blob2);
5147
});
5248

5349
it('should return empty array for non-existent blob hash', async () => {
@@ -59,31 +55,13 @@ export function describeBlobStore(getBlobStore: () => Promise<BlobStore>) {
5955
expect(retrievedBlobs).toEqual([]);
6056
});
6157

62-
it('should handle storing blobs with different indices', async () => {
63-
// Create blobs with different indices
64-
const blob1 = Blob.fromFields([Fr.random()]);
65-
const blob2 = Blob.fromFields([Fr.random()]);
66-
const blobWithIndex1 = new BlobWithIndex(blob1, 0);
67-
const blobWithIndex2 = new BlobWithIndex(blob2, 1);
68-
69-
await blobStore.addBlobs([blobWithIndex1, blobWithIndex2]);
70-
71-
const blobHash1 = blob1.getEthVersionedBlobHash();
72-
const blobHash2 = blob2.getEthVersionedBlobHash();
73-
74-
const retrievedBlobs = await blobStore.getBlobsByHashes([blobHash1, blobHash2]);
75-
76-
expect(retrievedBlobs[0].index).toBe(0);
77-
expect(retrievedBlobs[1].index).toBe(1);
78-
});
79-
8058
it('should handle retrieving subset of stored blobs', async () => {
8159
// Store multiple blobs
8260
const blob1 = Blob.fromFields([Fr.random()]);
8361
const blob2 = Blob.fromFields([Fr.random()]);
8462
const blob3 = Blob.fromFields([Fr.random()]);
8563

86-
await blobStore.addBlobs([new BlobWithIndex(blob1, 0), new BlobWithIndex(blob2, 1), new BlobWithIndex(blob3, 2)]);
64+
await blobStore.addBlobs([blob1, blob2, blob3]);
8765

8866
// Retrieve only some of them
8967
const blobHash1 = blob1.getEthVersionedBlobHash();
@@ -92,23 +70,22 @@ export function describeBlobStore(getBlobStore: () => Promise<BlobStore>) {
9270
const retrievedBlobs = await blobStore.getBlobsByHashes([blobHash1, blobHash3]);
9371

9472
expect(retrievedBlobs.length).toBe(2);
95-
expect(retrievedBlobs[0].blob).toEqual(blob1);
96-
expect(retrievedBlobs[1].blob).toEqual(blob3);
73+
expect(retrievedBlobs[0]).toEqual(blob1);
74+
expect(retrievedBlobs[1]).toEqual(blob3);
9775
});
9876

9977
it('should handle duplicate blob hashes in request', async () => {
10078
const blob = Blob.fromFields([Fr.random()]);
101-
const blobWithIndex = new BlobWithIndex(blob, 0);
10279
const blobHash = blob.getEthVersionedBlobHash();
10380

104-
await blobStore.addBlobs([blobWithIndex]);
81+
await blobStore.addBlobs([blob]);
10582

10683
// Request the same blob hash multiple times
10784
const retrievedBlobs = await blobStore.getBlobsByHashes([blobHash, blobHash]);
10885

10986
// Implementation may return duplicates or deduplicate - both are valid
11087
expect(retrievedBlobs.length).toBeGreaterThanOrEqual(1);
111-
expect(retrievedBlobs[0].blob).toEqual(blob);
88+
expect(retrievedBlobs[0]).toEqual(blob);
11289
});
11390

11491
it('should overwrite blob when storing with same hash', async () => {
@@ -117,21 +94,17 @@ export function describeBlobStore(getBlobStore: () => Promise<BlobStore>) {
11794
const blob1 = Blob.fromFields(fields);
11895
const blob2 = Blob.fromFields(fields);
11996

120-
// Store with different indices
121-
const blobWithIndex1 = new BlobWithIndex(blob1, 0);
122-
const blobWithIndex2 = new BlobWithIndex(blob2, 5);
123-
12497
const blobHash = blob1.getEthVersionedBlobHash();
12598

12699
// Store first blob
127-
await blobStore.addBlobs([blobWithIndex1]);
100+
await blobStore.addBlobs([blob1]);
128101

129-
// Overwrite with second blob (same hash, different index)
130-
await blobStore.addBlobs([blobWithIndex2]);
102+
// Overwrite with second blob (same hash)
103+
await blobStore.addBlobs([blob2]);
131104

132-
// Retrieve and verify it's the second blob (with index 5)
105+
// Retrieve and verify it exists
133106
const retrievedBlobs = await blobStore.getBlobsByHashes([blobHash]);
134107
expect(retrievedBlobs.length).toBe(1);
135-
expect(retrievedBlobs[0].index).toBe(5);
108+
expect(retrievedBlobs[0]).toEqual(blob1); // Same content
136109
});
137110
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import type { BlobWithIndex } from '../types/index.js';
1+
import type { Blob } from '@aztec/blob-lib';
22

33
export interface BlobStore {
44
/**
55
* Get blobs by their hashes
66
*/
7-
getBlobsByHashes: (blobHashes: Buffer[]) => Promise<BlobWithIndex[]>;
7+
getBlobsByHashes: (blobHashes: Buffer[]) => Promise<Blob[]>;
88
/**
99
* Add blobs to the store, indexed by their hashes
1010
*/
11-
addBlobs: (blobs: BlobWithIndex[]) => Promise<void>;
11+
addBlobs: (blobs: Blob[]) => Promise<void>;
1212
}

yarn-project/blob-client/src/blobstore/memory_blob_store.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
1+
import { Blob } from '@aztec/blob-lib';
12
import { bufferToHex } from '@aztec/foundation/string';
23

3-
import { BlobWithIndex } from '../types/index.js';
44
import type { BlobStore } from './interface.js';
55

66
export class MemoryBlobStore implements BlobStore {
77
private blobs: Map<string, Buffer> = new Map();
88

9-
public getBlobsByHashes(blobHashes: Buffer[]): Promise<BlobWithIndex[]> {
10-
const results: BlobWithIndex[] = [];
9+
public getBlobsByHashes(blobHashes: Buffer[]): Promise<Blob[]> {
10+
const results: Blob[] = [];
1111

1212
for (const blobHash of blobHashes) {
1313
const key = bufferToHex(blobHash);
1414
const blobBuffer = this.blobs.get(key);
1515
if (blobBuffer) {
16-
results.push(BlobWithIndex.fromBuffer(blobBuffer));
16+
results.push(Blob.fromBuffer(blobBuffer));
1717
}
1818
}
1919

2020
return Promise.resolve(results);
2121
}
2222

23-
public addBlobs(blobs: BlobWithIndex[]): Promise<void> {
23+
public addBlobs(blobs: Blob[]): Promise<void> {
2424
for (const blob of blobs) {
25-
const blobHash = blob.blob.getEthVersionedBlobHash();
25+
const blobHash = blob.getEthVersionedBlobHash();
2626
const key = bufferToHex(blobHash);
2727
this.blobs.set(key, blob.toBuffer());
2828
}

0 commit comments

Comments
 (0)