@aztec/blob-client 0.0.1-commit.9ef841308 → 0.0.1-commit.a89ec08
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/client/config.d.ts +1 -5
- package/dest/client/config.d.ts.map +1 -1
- package/dest/client/config.js +0 -10
- package/dest/client/factory.d.ts +1 -1
- package/dest/client/factory.d.ts.map +1 -1
- package/dest/client/factory.js +1 -7
- package/dest/client/http.d.ts +11 -19
- package/dest/client/http.d.ts.map +1 -1
- package/dest/client/http.js +114 -206
- package/dest/client/interface.d.ts +4 -13
- package/dest/client/interface.d.ts.map +1 -1
- package/dest/filestore/factory.d.ts +4 -5
- package/dest/filestore/factory.d.ts.map +1 -1
- package/dest/filestore/factory.js +4 -4
- package/package.json +7 -7
- package/src/client/config.ts +0 -16
- package/src/client/factory.ts +1 -8
- package/src/client/http.ts +108 -240
- package/src/client/interface.ts +3 -12
- package/src/filestore/factory.ts +2 -7
package/dest/client/http.js
CHANGED
|
@@ -18,9 +18,6 @@ export class HttpBlobClient {
|
|
|
18
18
|
fileStoreUploadClient;
|
|
19
19
|
disabled;
|
|
20
20
|
healthcheckUploadIntervalId;
|
|
21
|
-
/** Cached beacon genesis time (seconds since Unix epoch). Fetched once at startup. */ beaconGenesisTime;
|
|
22
|
-
/** Cached beacon slot duration in seconds. Fetched once at startup. */ beaconSecondsPerSlot;
|
|
23
|
-
/** Indexes of consensus hosts that serve blob sidecars (supernodes). Populated by testSources(). */ superNodeHostIndexes;
|
|
24
21
|
constructor(config, opts = {}){
|
|
25
22
|
this.opts = opts;
|
|
26
23
|
this.disabled = false;
|
|
@@ -74,7 +71,6 @@ export class HttpBlobClient {
|
|
|
74
71
|
let consensusNonSuperNodes = 0;
|
|
75
72
|
let archiveSources = 0;
|
|
76
73
|
let blobSinks = 0;
|
|
77
|
-
const detectedSuperNodes = new Set();
|
|
78
74
|
if (l1ConsensusHostUrls && l1ConsensusHostUrls.length > 0) {
|
|
79
75
|
for(let l1ConsensusHostIndex = 0; l1ConsensusHostIndex < l1ConsensusHostUrls.length; l1ConsensusHostIndex++){
|
|
80
76
|
const l1ConsensusHostUrl = l1ConsensusHostUrls[l1ConsensusHostIndex];
|
|
@@ -103,10 +99,9 @@ export class HttpBlobClient {
|
|
|
103
99
|
this.log.info(`L1 consensus host serves blob sidecars (supernode)`, {
|
|
104
100
|
l1ConsensusHostUrl
|
|
105
101
|
});
|
|
106
|
-
detectedSuperNodes.add(l1ConsensusHostIndex);
|
|
107
102
|
consensusSuperNodes++;
|
|
108
103
|
} else {
|
|
109
|
-
this.log.info(`L1 consensus host does not serve blob sidecars
|
|
104
|
+
this.log.info(`L1 consensus host does not serve blob sidecars`, {
|
|
110
105
|
l1ConsensusHostUrl
|
|
111
106
|
});
|
|
112
107
|
consensusNonSuperNodes++;
|
|
@@ -124,7 +119,6 @@ export class HttpBlobClient {
|
|
|
124
119
|
}
|
|
125
120
|
}
|
|
126
121
|
}
|
|
127
|
-
this.superNodeHostIndexes = detectedSuperNodes;
|
|
128
122
|
if (this.archiveClient) {
|
|
129
123
|
try {
|
|
130
124
|
const latest = await this.archiveClient.getLatestBlock();
|
|
@@ -197,25 +191,29 @@ export class HttpBlobClient {
|
|
|
197
191
|
}
|
|
198
192
|
}
|
|
199
193
|
/**
|
|
200
|
-
* Get the blob sidecar
|
|
194
|
+
* Get the blob sidecar
|
|
201
195
|
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
196
|
+
* If requesting from the blob client, we send the blobkHash
|
|
197
|
+
* If requesting from the beacon node, we send the slot number
|
|
198
|
+
*
|
|
199
|
+
* Source ordering depends on sync state:
|
|
200
|
+
* - Historical sync: blob client → FileStore → L1 consensus → Archive
|
|
201
|
+
* - Near tip sync: blob client → FileStore → L1 consensus → FileStore (with retries) → Archive (eg blobscan)
|
|
205
202
|
*
|
|
206
203
|
* @param blockHash - The block hash
|
|
207
204
|
* @param blobHashes - The blob hashes to fetch
|
|
208
|
-
* @param opts - Options
|
|
205
|
+
* @param opts - Options including isHistoricalSync flag
|
|
209
206
|
* @returns The blobs
|
|
210
207
|
*/ async getBlobSidecar(blockHash, blobHashes, opts) {
|
|
211
208
|
if (this.disabled) {
|
|
212
209
|
this.log.warn('Blob storage is disabled, returning empty blob sidecar');
|
|
213
210
|
return [];
|
|
214
211
|
}
|
|
212
|
+
const isHistoricalSync = opts?.isHistoricalSync ?? false;
|
|
215
213
|
// Accumulate blobs across sources, preserving order and handling duplicates
|
|
216
214
|
// resultBlobs[i] will contain the blob for blobHashes[i], or undefined if not yet found
|
|
217
215
|
const resultBlobs = new Array(blobHashes.length).fill(undefined);
|
|
218
|
-
// Helper to get
|
|
216
|
+
// Helper to get missing blob hashes that we still need to fetch
|
|
219
217
|
const getMissingBlobHashes = ()=>blobHashes.map((bh, i)=>resultBlobs[i] === undefined ? bh : undefined).filter((bh)=>bh !== undefined);
|
|
220
218
|
// Return the result, ignoring any undefined ones
|
|
221
219
|
const getFilledBlobs = ()=>resultBlobs.filter((b)=>b !== undefined);
|
|
@@ -237,69 +235,80 @@ export class HttpBlobClient {
|
|
|
237
235
|
}
|
|
238
236
|
return blobs;
|
|
239
237
|
};
|
|
238
|
+
const { l1ConsensusHostUrls } = this.config;
|
|
240
239
|
const ctx = {
|
|
241
240
|
blockHash,
|
|
242
241
|
blobHashes: blobHashes.map(bufferToHex)
|
|
243
242
|
};
|
|
244
|
-
//
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
slotNumber = await this.resolveSlotNumber(blockHash, opts);
|
|
250
|
-
slotResolved = true;
|
|
243
|
+
// Try filestore (quick, no retries) - useful for both historical and near-tip sync
|
|
244
|
+
if (this.fileStoreClients.length > 0 && getMissingBlobHashes().length > 0) {
|
|
245
|
+
await this.tryFileStores(getMissingBlobHashes, fillResults, ctx);
|
|
246
|
+
if (getMissingBlobHashes().length === 0) {
|
|
247
|
+
return returnWithCallback(getFilledBlobs());
|
|
251
248
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
if (getMissingBlobHashes().length > 0) {
|
|
288
|
-
throw new Error('Still missing blobs after trying all primary sources');
|
|
249
|
+
}
|
|
250
|
+
const missingAfterSink = getMissingBlobHashes();
|
|
251
|
+
if (missingAfterSink.length > 0 && l1ConsensusHostUrls && l1ConsensusHostUrls.length > 0) {
|
|
252
|
+
// The beacon api can query by slot number, so we get that first
|
|
253
|
+
const consensusCtx = {
|
|
254
|
+
l1ConsensusHostUrls,
|
|
255
|
+
...ctx
|
|
256
|
+
};
|
|
257
|
+
this.log.trace(`Attempting to get slot number for block hash`, consensusCtx);
|
|
258
|
+
const slotNumber = await this.getSlotNumber(blockHash);
|
|
259
|
+
this.log.debug(`Got slot number ${slotNumber} from consensus host for querying blobs`, consensusCtx);
|
|
260
|
+
if (slotNumber) {
|
|
261
|
+
let l1ConsensusHostUrl;
|
|
262
|
+
for(let l1ConsensusHostIndex = 0; l1ConsensusHostIndex < l1ConsensusHostUrls.length; l1ConsensusHostIndex++){
|
|
263
|
+
const missingHashes = getMissingBlobHashes();
|
|
264
|
+
if (missingHashes.length === 0) {
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
l1ConsensusHostUrl = l1ConsensusHostUrls[l1ConsensusHostIndex];
|
|
268
|
+
this.log.trace(`Attempting to get ${missingHashes.length} blobs from consensus host`, {
|
|
269
|
+
slotNumber,
|
|
270
|
+
l1ConsensusHostUrl,
|
|
271
|
+
...ctx
|
|
272
|
+
});
|
|
273
|
+
const blobs = await this.getBlobsFromHost(l1ConsensusHostUrl, slotNumber, l1ConsensusHostIndex);
|
|
274
|
+
const result = await fillResults(blobs);
|
|
275
|
+
this.log.debug(`Got ${blobs.length} blobs from consensus host (total: ${result.length}/${blobHashes.length})`, {
|
|
276
|
+
slotNumber,
|
|
277
|
+
l1ConsensusHostUrl,
|
|
278
|
+
...ctx
|
|
279
|
+
});
|
|
280
|
+
if (result.length === blobHashes.length) {
|
|
281
|
+
return returnWithCallback(result);
|
|
282
|
+
}
|
|
289
283
|
}
|
|
290
|
-
}
|
|
291
|
-
return returnWithCallback(getFilledBlobs());
|
|
292
|
-
} catch {
|
|
293
|
-
// Exhausted retries, continue to archive fallback
|
|
284
|
+
}
|
|
294
285
|
}
|
|
295
|
-
//
|
|
296
|
-
|
|
297
|
-
if (
|
|
286
|
+
// For near-tip sync, retry filestores with backoff (eventual consistency)
|
|
287
|
+
// This handles the case where blobs are still being uploaded by other validators
|
|
288
|
+
if (!isHistoricalSync && this.fileStoreClients.length > 0 && getMissingBlobHashes().length > 0) {
|
|
289
|
+
try {
|
|
290
|
+
await retry(async ()=>{
|
|
291
|
+
await this.tryFileStores(getMissingBlobHashes, fillResults, ctx);
|
|
292
|
+
if (getMissingBlobHashes().length > 0) {
|
|
293
|
+
throw new Error('Still missing blobs from filestores');
|
|
294
|
+
}
|
|
295
|
+
}, 'filestore blob retrieval', makeBackoff([
|
|
296
|
+
1,
|
|
297
|
+
1,
|
|
298
|
+
2
|
|
299
|
+
]), this.log, true);
|
|
300
|
+
return returnWithCallback(getFilledBlobs());
|
|
301
|
+
} catch {
|
|
302
|
+
// Exhausted retries, continue to archive fallback
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
const missingAfterConsensus = getMissingBlobHashes();
|
|
306
|
+
if (missingAfterConsensus.length > 0 && this.archiveClient) {
|
|
298
307
|
const archiveCtx = {
|
|
299
308
|
archiveUrl: this.archiveClient.getBaseUrl(),
|
|
300
309
|
...ctx
|
|
301
310
|
};
|
|
302
|
-
this.log.trace(`Attempting to get ${
|
|
311
|
+
this.log.trace(`Attempting to get ${missingAfterConsensus.length} blobs from archive`, archiveCtx);
|
|
303
312
|
const allBlobs = await this.archiveClient.getBlobsFromBlock(blockHash);
|
|
304
313
|
if (!allBlobs) {
|
|
305
314
|
this.log.debug('No blobs found from archive client', archiveCtx);
|
|
@@ -315,63 +324,13 @@ export class HttpBlobClient {
|
|
|
315
324
|
const result = getFilledBlobs();
|
|
316
325
|
if (result.length < blobHashes.length) {
|
|
317
326
|
this.log.warn(`Failed to fetch all blobs for ${blockHash} from all blob sources (got ${result.length}/${blobHashes.length})`, {
|
|
318
|
-
l1ConsensusHostUrls
|
|
327
|
+
l1ConsensusHostUrls,
|
|
319
328
|
archiveUrl: this.archiveClient?.getBaseUrl(),
|
|
320
329
|
fileStoreUrls: this.fileStoreClients.map((c)=>c.getBaseUrl())
|
|
321
330
|
});
|
|
322
331
|
}
|
|
323
332
|
return returnWithCallback(result);
|
|
324
333
|
}
|
|
325
|
-
/** Resolves the beacon slot number for the given block hash. Returns undefined if no consensus hosts. */ resolveSlotNumber(blockHash, opts) {
|
|
326
|
-
const { l1ConsensusHostUrls } = this.config;
|
|
327
|
-
if (!l1ConsensusHostUrls || l1ConsensusHostUrls.length === 0) {
|
|
328
|
-
return undefined;
|
|
329
|
-
}
|
|
330
|
-
// If no supernodes, no point resolving the slot
|
|
331
|
-
if (this.superNodeHostIndexes && this.superNodeHostIndexes.size === 0) {
|
|
332
|
-
return undefined;
|
|
333
|
-
}
|
|
334
|
-
return this.getSlotNumber(blockHash, opts?.parentBeaconBlockRoot, opts?.l1BlockTimestamp);
|
|
335
|
-
}
|
|
336
|
-
/**
|
|
337
|
-
* Try all supernode consensus hosts for blob sidecars.
|
|
338
|
-
* Skips hosts that were detected as non-supernodes during testSources().
|
|
339
|
-
*/ async tryConsensusHosts(getSlotNumber, getMissingBlobHashes, fillResults, ctx) {
|
|
340
|
-
const { l1ConsensusHostUrls } = this.config;
|
|
341
|
-
if (!l1ConsensusHostUrls || l1ConsensusHostUrls.length === 0) {
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
const slotNumber = await getSlotNumber();
|
|
345
|
-
if (!slotNumber) {
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
for(let l1ConsensusHostIndex = 0; l1ConsensusHostIndex < l1ConsensusHostUrls.length; l1ConsensusHostIndex++){
|
|
349
|
-
const missingHashes = getMissingBlobHashes();
|
|
350
|
-
if (missingHashes.length === 0) {
|
|
351
|
-
break;
|
|
352
|
-
}
|
|
353
|
-
// Skip non-supernode hosts if we've already detected supernodes
|
|
354
|
-
if (this.superNodeHostIndexes && !this.superNodeHostIndexes.has(l1ConsensusHostIndex)) {
|
|
355
|
-
this.log.trace(`Skipping non-supernode consensus host`, {
|
|
356
|
-
l1ConsensusHostUrl: l1ConsensusHostUrls[l1ConsensusHostIndex]
|
|
357
|
-
});
|
|
358
|
-
continue;
|
|
359
|
-
}
|
|
360
|
-
const l1ConsensusHostUrl = l1ConsensusHostUrls[l1ConsensusHostIndex];
|
|
361
|
-
this.log.trace(`Attempting to get ${missingHashes.length} blobs from consensus host`, {
|
|
362
|
-
slotNumber,
|
|
363
|
-
l1ConsensusHostUrl,
|
|
364
|
-
...ctx
|
|
365
|
-
});
|
|
366
|
-
const blobs = await this.getBlobsFromHost(l1ConsensusHostUrl, slotNumber, l1ConsensusHostIndex, missingHashes);
|
|
367
|
-
const result = await fillResults(blobs);
|
|
368
|
-
this.log.debug(`Got ${blobs.length} blobs from consensus host (total: ${result.length}/${ctx.blobHashes.length})`, {
|
|
369
|
-
slotNumber,
|
|
370
|
-
l1ConsensusHostUrl,
|
|
371
|
-
...ctx
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
334
|
/**
|
|
376
335
|
* Try all filestores once (shuffled for load distribution).
|
|
377
336
|
* @param getMissingBlobHashes - Function to get remaining blob hashes to fetch
|
|
@@ -410,14 +369,14 @@ export class HttpBlobClient {
|
|
|
410
369
|
}
|
|
411
370
|
}
|
|
412
371
|
async getBlobSidecarFrom(hostUrl, blockHashOrSlot, blobHashes = [], l1ConsensusHostIndex) {
|
|
413
|
-
const blobs = await this.getBlobsFromHost(hostUrl, blockHashOrSlot, l1ConsensusHostIndex
|
|
372
|
+
const blobs = await this.getBlobsFromHost(hostUrl, blockHashOrSlot, l1ConsensusHostIndex);
|
|
414
373
|
return (await processFetchedBlobs(blobs, blobHashes, this.log)).filter((b)=>b !== undefined);
|
|
415
374
|
}
|
|
416
|
-
async getBlobsFromHost(hostUrl, blockHashOrSlot, l1ConsensusHostIndex
|
|
375
|
+
async getBlobsFromHost(hostUrl, blockHashOrSlot, l1ConsensusHostIndex) {
|
|
417
376
|
try {
|
|
418
|
-
let res = await this.fetchBlobSidecars(hostUrl, blockHashOrSlot, l1ConsensusHostIndex
|
|
377
|
+
let res = await this.fetchBlobSidecars(hostUrl, blockHashOrSlot, l1ConsensusHostIndex);
|
|
419
378
|
if (res.ok) {
|
|
420
|
-
return
|
|
379
|
+
return parseBlobJsonsFromResponse(await res.json(), this.log);
|
|
421
380
|
}
|
|
422
381
|
if (res.status === 404 && typeof blockHashOrSlot === 'number') {
|
|
423
382
|
const latestSlot = await this.getLatestSlotNumber(hostUrl, l1ConsensusHostIndex);
|
|
@@ -430,9 +389,9 @@ export class HttpBlobClient {
|
|
|
430
389
|
let currentSlot = blockHashOrSlot + 1;
|
|
431
390
|
while(res.status === 404 && maxRetries > 0 && latestSlot !== undefined && currentSlot <= latestSlot){
|
|
432
391
|
this.log.debug(`Trying slot ${currentSlot}`);
|
|
433
|
-
res = await this.fetchBlobSidecars(hostUrl, currentSlot, l1ConsensusHostIndex
|
|
392
|
+
res = await this.fetchBlobSidecars(hostUrl, currentSlot, l1ConsensusHostIndex);
|
|
434
393
|
if (res.ok) {
|
|
435
|
-
return
|
|
394
|
+
return parseBlobJsonsFromResponse(await res.json(), this.log);
|
|
436
395
|
}
|
|
437
396
|
currentSlot++;
|
|
438
397
|
maxRetries--;
|
|
@@ -449,22 +408,14 @@ export class HttpBlobClient {
|
|
|
449
408
|
return [];
|
|
450
409
|
}
|
|
451
410
|
}
|
|
452
|
-
fetchBlobSidecars(hostUrl, blockHashOrSlot, l1ConsensusHostIndex
|
|
453
|
-
|
|
454
|
-
if (blobHashes && blobHashes.length > 0) {
|
|
455
|
-
const params = new URLSearchParams();
|
|
456
|
-
for (const hash of blobHashes){
|
|
457
|
-
params.append('versioned_hashes', `0x${hash.toString('hex')}`);
|
|
458
|
-
}
|
|
459
|
-
baseUrl += `?${params.toString()}`;
|
|
460
|
-
}
|
|
411
|
+
fetchBlobSidecars(hostUrl, blockHashOrSlot, l1ConsensusHostIndex) {
|
|
412
|
+
const baseUrl = `${hostUrl}/eth/v1/beacon/blob_sidecars/${blockHashOrSlot}`;
|
|
461
413
|
const { url, ...options } = getBeaconNodeFetchOptions(baseUrl, this.config, l1ConsensusHostIndex);
|
|
462
414
|
this.log.debug(`Fetching blob sidecar for ${blockHashOrSlot}`, {
|
|
463
415
|
url,
|
|
464
416
|
...options
|
|
465
417
|
});
|
|
466
|
-
|
|
467
|
-
return fetch(url, options);
|
|
418
|
+
return this.fetch(url, options);
|
|
468
419
|
}
|
|
469
420
|
async getLatestSlotNumber(hostUrl, l1ConsensusHostIndex) {
|
|
470
421
|
try {
|
|
@@ -504,45 +455,36 @@ export class HttpBlobClient {
|
|
|
504
455
|
*
|
|
505
456
|
* @param blockHash - The block hash
|
|
506
457
|
* @returns The slot number
|
|
507
|
-
*/ async getSlotNumber(blockHash
|
|
458
|
+
*/ async getSlotNumber(blockHash) {
|
|
508
459
|
const { l1ConsensusHostUrls, l1RpcUrls } = this.config;
|
|
509
460
|
if (!l1ConsensusHostUrls || l1ConsensusHostUrls.length === 0) {
|
|
510
461
|
this.log.debug('No consensus host url configured');
|
|
511
462
|
return undefined;
|
|
512
463
|
}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
this.log.debug(`Computed slot ${slot} from L1 block timestamp`, {
|
|
517
|
-
l1BlockTimestamp
|
|
518
|
-
});
|
|
519
|
-
return slot;
|
|
464
|
+
if (!l1RpcUrls || l1RpcUrls.length === 0) {
|
|
465
|
+
this.log.debug('No execution host url configured');
|
|
466
|
+
return undefined;
|
|
520
467
|
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
468
|
+
// Ping execution node to get the parentBeaconBlockRoot for this block
|
|
469
|
+
let parentBeaconBlockRoot;
|
|
470
|
+
const client = createPublicClient({
|
|
471
|
+
transport: makeL1HttpTransport(l1RpcUrls, {
|
|
472
|
+
timeout: this.config.l1HttpTimeoutMS
|
|
473
|
+
})
|
|
474
|
+
});
|
|
475
|
+
try {
|
|
476
|
+
const res = await client.request({
|
|
477
|
+
method: 'eth_getBlockByHash',
|
|
478
|
+
params: [
|
|
479
|
+
blockHash,
|
|
480
|
+
/*tx flag*/ false
|
|
481
|
+
]
|
|
531
482
|
});
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
method: 'eth_getBlockByHash',
|
|
535
|
-
params: [
|
|
536
|
-
blockHash,
|
|
537
|
-
/*tx flag*/ false
|
|
538
|
-
]
|
|
539
|
-
});
|
|
540
|
-
if (res.parentBeaconBlockRoot) {
|
|
541
|
-
parentBeaconBlockRoot = res.parentBeaconBlockRoot;
|
|
542
|
-
}
|
|
543
|
-
} catch (err) {
|
|
544
|
-
this.log.error(`Error getting parent beacon block root`, err);
|
|
483
|
+
if (res.parentBeaconBlockRoot) {
|
|
484
|
+
parentBeaconBlockRoot = res.parentBeaconBlockRoot;
|
|
545
485
|
}
|
|
486
|
+
} catch (err) {
|
|
487
|
+
this.log.error(`Error getting parent beacon block root`, err);
|
|
546
488
|
}
|
|
547
489
|
if (!parentBeaconBlockRoot) {
|
|
548
490
|
this.log.error(`No parent beacon block root found for block ${blockHash}`);
|
|
@@ -574,10 +516,8 @@ export class HttpBlobClient {
|
|
|
574
516
|
}
|
|
575
517
|
/**
|
|
576
518
|
* Start the blob client.
|
|
577
|
-
*
|
|
578
|
-
* then uploads the initial healthcheck file (awaited) and starts periodic uploads.
|
|
519
|
+
* Uploads the initial healthcheck file (awaited) and starts periodic uploads.
|
|
579
520
|
*/ async start() {
|
|
580
|
-
await this.fetchBeaconConfig();
|
|
581
521
|
if (!this.fileStoreUploadClient) {
|
|
582
522
|
return;
|
|
583
523
|
}
|
|
@@ -596,40 +536,6 @@ export class HttpBlobClient {
|
|
|
596
536
|
}, intervalMs);
|
|
597
537
|
}
|
|
598
538
|
/**
|
|
599
|
-
* Fetches and caches beacon genesis time and slot duration from the first available consensus host.
|
|
600
|
-
* These static values enable timestamp-based slot resolution, eliminating the per-fetch headers call.
|
|
601
|
-
* Logs a warning and leaves fields undefined if all hosts fail, callers fall back gracefully.
|
|
602
|
-
*/ async fetchBeaconConfig() {
|
|
603
|
-
const { l1ConsensusHostUrls } = this.config;
|
|
604
|
-
if (!l1ConsensusHostUrls || l1ConsensusHostUrls.length === 0) {
|
|
605
|
-
return;
|
|
606
|
-
}
|
|
607
|
-
for(let i = 0; i < l1ConsensusHostUrls.length; i++){
|
|
608
|
-
try {
|
|
609
|
-
const { url: genesisUrl, ...genesisOptions } = getBeaconNodeFetchOptions(`${l1ConsensusHostUrls[i]}/eth/v1/config/genesis`, this.config, i);
|
|
610
|
-
const { url: specUrl, ...specOptions } = getBeaconNodeFetchOptions(`${l1ConsensusHostUrls[i]}/eth/v1/config/spec`, this.config, i);
|
|
611
|
-
const [genesisRes, specRes] = await Promise.all([
|
|
612
|
-
this.fetch(genesisUrl, genesisOptions),
|
|
613
|
-
this.fetch(specUrl, specOptions)
|
|
614
|
-
]);
|
|
615
|
-
if (genesisRes.ok && specRes.ok) {
|
|
616
|
-
const genesis = await genesisRes.json();
|
|
617
|
-
const spec = await specRes.json();
|
|
618
|
-
this.beaconGenesisTime = BigInt(genesis.data.genesisTime);
|
|
619
|
-
this.beaconSecondsPerSlot = parseInt(spec.data.secondsPerSlot);
|
|
620
|
-
this.log.debug(`Fetched beacon genesis config`, {
|
|
621
|
-
genesisTime: this.beaconGenesisTime,
|
|
622
|
-
secondsPerSlot: this.beaconSecondsPerSlot
|
|
623
|
-
});
|
|
624
|
-
return;
|
|
625
|
-
}
|
|
626
|
-
} catch (err) {
|
|
627
|
-
this.log.warn(`Failed to fetch beacon config from host ${l1ConsensusHostUrls[i]}`, err);
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
this.log.warn('Could not fetch beacon genesis config from any consensus host — will use headers call fallback');
|
|
631
|
-
}
|
|
632
|
-
/**
|
|
633
539
|
* Stop the blob client, clearing any periodic tasks.
|
|
634
540
|
*/ stop() {
|
|
635
541
|
if (this.healthcheckUploadIntervalId) {
|
|
@@ -638,9 +544,10 @@ export class HttpBlobClient {
|
|
|
638
544
|
}
|
|
639
545
|
}
|
|
640
546
|
}
|
|
641
|
-
|
|
547
|
+
function parseBlobJsonsFromResponse(response, logger) {
|
|
642
548
|
try {
|
|
643
|
-
|
|
549
|
+
const blobs = response.data.map(parseBlobJson);
|
|
550
|
+
return blobs;
|
|
644
551
|
} catch (err) {
|
|
645
552
|
logger.error(`Error parsing blob json from response`, err);
|
|
646
553
|
return [];
|
|
@@ -650,9 +557,10 @@ async function parseBlobJsonsFromResponse(response, logger) {
|
|
|
650
557
|
// https://ethereum.github.io/beacon-APIs/?urls.primaryName=dev#/Beacon/getBlobSidecars
|
|
651
558
|
// Here we attempt to parse the response data to Buffer, and check the lengths (via Blob's constructor), to avoid
|
|
652
559
|
// throwing an error down the line when calling Blob.fromJson().
|
|
653
|
-
|
|
654
|
-
const blobBuffer = Buffer.from(
|
|
655
|
-
const
|
|
560
|
+
function parseBlobJson(data) {
|
|
561
|
+
const blobBuffer = Buffer.from(data.blob.slice(2), 'hex');
|
|
562
|
+
const commitmentBuffer = Buffer.from(data.kzg_commitment.slice(2), 'hex');
|
|
563
|
+
const blob = new Blob(blobBuffer, commitmentBuffer);
|
|
656
564
|
return blob.toJSON();
|
|
657
565
|
}
|
|
658
566
|
// Returns an array that maps each blob hash to the corresponding blob, or undefined if the blob is not found
|
|
@@ -5,20 +5,11 @@ import type { Blob } from '@aztec/blob-lib';
|
|
|
5
5
|
export interface GetBlobSidecarOptions {
|
|
6
6
|
/**
|
|
7
7
|
* True if the archiver is catching up (historical sync), false if near tip.
|
|
8
|
-
*
|
|
8
|
+
* This affects source ordering:
|
|
9
|
+
* - Historical: FileStore first (data should exist), then L1 consensus, then archive (eg. blobscan)
|
|
10
|
+
* - Near tip: FileStore first with no retries (data should exist), L1 consensus second (freshest data), then FileStore with retries, then archive (eg. blobscan)
|
|
9
11
|
*/
|
|
10
12
|
isHistoricalSync?: boolean;
|
|
11
|
-
/**
|
|
12
|
-
* The parent beacon block root for the L1 block containing the blobs.
|
|
13
|
-
* If provided, skips the eth_getBlockByHash execution RPC call inside getSlotNumber.
|
|
14
|
-
*/
|
|
15
|
-
parentBeaconBlockRoot?: string;
|
|
16
|
-
/**
|
|
17
|
-
* The timestamp of the L1 execution block containing the blobs.
|
|
18
|
-
* When provided alongside a cached beacon genesis config (fetched at startup), allows computing
|
|
19
|
-
* the beacon slot directly via timestamp math, skipping the beacon headers network call entirely.
|
|
20
|
-
*/
|
|
21
|
-
l1BlockTimestamp?: bigint;
|
|
22
13
|
}
|
|
23
14
|
export interface BlobClientInterface {
|
|
24
15
|
/** Sends the given blobs to the filestore, to be indexed by blob hash. */
|
|
@@ -34,4 +25,4 @@ export interface BlobClientInterface {
|
|
|
34
25
|
/** Returns true if this client can upload blobs to filestore. */
|
|
35
26
|
canUpload(): boolean;
|
|
36
27
|
}
|
|
37
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
28
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZXJmYWNlLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY2xpZW50L2ludGVyZmFjZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxJQUFJLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUU1Qzs7R0FFRztBQUNILE1BQU0sV0FBVyxxQkFBcUI7SUFDcEM7Ozs7O09BS0c7SUFDSCxnQkFBZ0IsQ0FBQyxFQUFFLE9BQU8sQ0FBQztDQUM1QjtBQUVELE1BQU0sV0FBVyxtQkFBbUI7SUFDbEMsMEVBQTBFO0lBQzFFLG9CQUFvQixDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDdEQscUVBQXFFO0lBQ3JFLGNBQWMsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLFVBQVUsQ0FBQyxFQUFFLE1BQU0sRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFLHFCQUFxQixHQUFHLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ3RHLDZFQUE2RTtJQUM3RSxLQUFLLENBQUMsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDeEIsb0ZBQW9GO0lBQ3BGLFdBQVcsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDN0IsMERBQTBEO0lBQzFELElBQUksQ0FBQyxJQUFJLElBQUksQ0FBQztJQUNkLGlFQUFpRTtJQUNqRSxTQUFTLElBQUksT0FBTyxDQUFDO0NBQ3RCIn0=
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/client/interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC
|
|
1
|
+
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/client/interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,0EAA0E;IAC1E,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtD,qEAAqE;IACrE,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACtG,6EAA6E;IAC7E,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,oFAAoF;IACpF,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,0DAA0D;IAC1D,IAAI,CAAC,IAAI,IAAI,CAAC;IACd,iEAAiE;IACjE,SAAS,IAAI,OAAO,CAAC;CACtB"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { type Logger } from '@aztec/foundation/log';
|
|
2
|
-
import { type HttpFileStoreOptions } from '@aztec/stdlib/file-store';
|
|
3
2
|
import { FileStoreBlobClient } from './filestore_blob_client.js';
|
|
4
3
|
/**
|
|
5
4
|
* Metadata required to construct the base path for blob storage.
|
|
@@ -26,8 +25,8 @@ export declare function makeBlobBasePath(metadata: BlobFileStoreMetadata): strin
|
|
|
26
25
|
* @param logger - Optional logger
|
|
27
26
|
* @returns A FileStoreBlobClient for reading blobs, or undefined if storeUrl is undefined
|
|
28
27
|
*/
|
|
29
|
-
export declare function createReadOnlyFileStoreBlobClient(storeUrl: string, metadata: BlobFileStoreMetadata, logger?: Logger
|
|
30
|
-
export declare function createReadOnlyFileStoreBlobClient(storeUrl: string | undefined, metadata: BlobFileStoreMetadata, logger?: Logger
|
|
28
|
+
export declare function createReadOnlyFileStoreBlobClient(storeUrl: string, metadata: BlobFileStoreMetadata, logger?: Logger): Promise<FileStoreBlobClient>;
|
|
29
|
+
export declare function createReadOnlyFileStoreBlobClient(storeUrl: string | undefined, metadata: BlobFileStoreMetadata, logger?: Logger): Promise<FileStoreBlobClient | undefined>;
|
|
31
30
|
/**
|
|
32
31
|
* Creates multiple read-only FileStoreBlobClients from an array of URLs.
|
|
33
32
|
*
|
|
@@ -36,7 +35,7 @@ export declare function createReadOnlyFileStoreBlobClient(storeUrl: string | und
|
|
|
36
35
|
* @param logger - Optional logger
|
|
37
36
|
* @returns Array of FileStoreBlobClients (excludes any that failed to create)
|
|
38
37
|
*/
|
|
39
|
-
export declare function createReadOnlyFileStoreBlobClients(storeUrls: string[] | undefined, metadata: BlobFileStoreMetadata, logger?: Logger
|
|
38
|
+
export declare function createReadOnlyFileStoreBlobClients(storeUrls: string[] | undefined, metadata: BlobFileStoreMetadata, logger?: Logger): Promise<FileStoreBlobClient[]>;
|
|
40
39
|
/**
|
|
41
40
|
* Creates a writable FileStoreBlobClient for uploading blobs.
|
|
42
41
|
* Note: https:// URLs are not supported for upload, only s3://, gs://, or file://.
|
|
@@ -48,4 +47,4 @@ export declare function createReadOnlyFileStoreBlobClients(storeUrls: string[] |
|
|
|
48
47
|
*/
|
|
49
48
|
export declare function createWritableFileStoreBlobClient(storeUrl: string, metadata: BlobFileStoreMetadata, logger?: Logger): Promise<FileStoreBlobClient>;
|
|
50
49
|
export declare function createWritableFileStoreBlobClient(storeUrl: string | undefined, metadata: BlobFileStoreMetadata, logger?: Logger): Promise<FileStoreBlobClient | undefined>;
|
|
51
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
50
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFjdG9yeS5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ZpbGVzdG9yZS9mYWN0b3J5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxLQUFLLE1BQU0sRUFBZ0IsTUFBTSx1QkFBdUIsQ0FBQztBQVFsRSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUVqRTs7O0dBR0c7QUFDSCxNQUFNLFdBQVcscUJBQXFCO0lBQ3BDLHNCQUFzQjtJQUN0QixTQUFTLEVBQUUsTUFBTSxDQUFDO0lBQ2xCLHlCQUF5QjtJQUN6QixhQUFhLEVBQUUsTUFBTSxDQUFDO0lBQ3RCLDhEQUE4RDtJQUM5RCxhQUFhLEVBQUUsTUFBTSxDQUFDO0NBQ3ZCO0FBRUQ7OztHQUdHO0FBQ0gsd0JBQWdCLGdCQUFnQixDQUFDLFFBQVEsRUFBRSxxQkFBcUIsR0FBRyxNQUFNLENBS3hFO0FBRUQ7Ozs7Ozs7R0FPRztBQUNILHdCQUFzQixpQ0FBaUMsQ0FDckQsUUFBUSxFQUFFLE1BQU0sRUFDaEIsUUFBUSxFQUFFLHFCQUFxQixFQUMvQixNQUFNLENBQUMsRUFBRSxNQUFNLEdBQ2QsT0FBTyxDQUFDLG1CQUFtQixDQUFDLENBQUM7QUFDaEMsd0JBQXNCLGlDQUFpQyxDQUNyRCxRQUFRLEVBQUUsTUFBTSxHQUFHLFNBQVMsRUFDNUIsUUFBUSxFQUFFLHFCQUFxQixFQUMvQixNQUFNLENBQUMsRUFBRSxNQUFNLEdBQ2QsT0FBTyxDQUFDLG1CQUFtQixHQUFHLFNBQVMsQ0FBQyxDQUFDO0FBbUI1Qzs7Ozs7OztHQU9HO0FBQ0gsd0JBQXNCLGtDQUFrQyxDQUN0RCxTQUFTLEVBQUUsTUFBTSxFQUFFLEdBQUcsU0FBUyxFQUMvQixRQUFRLEVBQUUscUJBQXFCLEVBQy9CLE1BQU0sQ0FBQyxFQUFFLE1BQU0sR0FDZCxPQUFPLENBQUMsbUJBQW1CLEVBQUUsQ0FBQyxDQW9CaEM7QUFFRDs7Ozs7Ozs7R0FRRztBQUNILHdCQUFzQixpQ0FBaUMsQ0FDckQsUUFBUSxFQUFFLE1BQU0sRUFDaEIsUUFBUSxFQUFFLHFCQUFxQixFQUMvQixNQUFNLENBQUMsRUFBRSxNQUFNLEdBQ2QsT0FBTyxDQUFDLG1CQUFtQixDQUFDLENBQUM7QUFDaEMsd0JBQXNCLGlDQUFpQyxDQUNyRCxRQUFRLEVBQUUsTUFBTSxHQUFHLFNBQVMsRUFDNUIsUUFBUSxFQUFFLHFCQUFxQixFQUMvQixNQUFNLENBQUMsRUFBRSxNQUFNLEdBQ2QsT0FBTyxDQUFDLG1CQUFtQixHQUFHLFNBQVMsQ0FBQyxDQUFDIn0=
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/filestore/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/filestore/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAQlE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,sBAAsB;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,yBAAyB;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,MAAM,CAKxE;AAED;;;;;;;GAOG;AACH,wBAAsB,iCAAiC,CACrD,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,qBAAqB,EAC/B,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,mBAAmB,CAAC,CAAC;AAChC,wBAAsB,iCAAiC,CACrD,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,QAAQ,EAAE,qBAAqB,EAC/B,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC,CAAC;AAmB5C;;;;;;;GAOG;AACH,wBAAsB,kCAAkC,CACtD,SAAS,EAAE,MAAM,EAAE,GAAG,SAAS,EAC/B,QAAQ,EAAE,qBAAqB,EAC/B,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAoBhC;AAED;;;;;;;;GAQG;AACH,wBAAsB,iCAAiC,CACrD,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,qBAAqB,EAC/B,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,mBAAmB,CAAC,CAAC;AAChC,wBAAsB,iCAAiC,CACrD,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,QAAQ,EAAE,qBAAqB,EAC/B,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC,CAAC"}
|
|
@@ -10,7 +10,7 @@ import { FileStoreBlobClient } from './filestore_blob_client.js';
|
|
|
10
10
|
const normalizedAddress = rollupAddress.toLowerCase().replace(/^0x/, '');
|
|
11
11
|
return `aztec-${l1ChainId}-${rollupVersion}-0x${normalizedAddress}`;
|
|
12
12
|
}
|
|
13
|
-
export async function createReadOnlyFileStoreBlobClient(storeUrl, metadata, logger
|
|
13
|
+
export async function createReadOnlyFileStoreBlobClient(storeUrl, metadata, logger) {
|
|
14
14
|
if (!storeUrl) {
|
|
15
15
|
return undefined;
|
|
16
16
|
}
|
|
@@ -20,7 +20,7 @@ export async function createReadOnlyFileStoreBlobClient(storeUrl, metadata, logg
|
|
|
20
20
|
storeUrl,
|
|
21
21
|
basePath
|
|
22
22
|
});
|
|
23
|
-
const store = await createReadOnlyFileStore(storeUrl, log
|
|
23
|
+
const store = await createReadOnlyFileStore(storeUrl, log);
|
|
24
24
|
return new FileStoreBlobClient(store, basePath, log);
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
@@ -30,7 +30,7 @@ export async function createReadOnlyFileStoreBlobClient(storeUrl, metadata, logg
|
|
|
30
30
|
* @param metadata - Chain metadata for constructing the base path
|
|
31
31
|
* @param logger - Optional logger
|
|
32
32
|
* @returns Array of FileStoreBlobClients (excludes any that failed to create)
|
|
33
|
-
*/ export async function createReadOnlyFileStoreBlobClients(storeUrls, metadata, logger
|
|
33
|
+
*/ export async function createReadOnlyFileStoreBlobClients(storeUrls, metadata, logger) {
|
|
34
34
|
if (!storeUrls || storeUrls.length === 0) {
|
|
35
35
|
return [];
|
|
36
36
|
}
|
|
@@ -38,7 +38,7 @@ export async function createReadOnlyFileStoreBlobClient(storeUrl, metadata, logg
|
|
|
38
38
|
const clients = [];
|
|
39
39
|
for (const storeUrl of storeUrls){
|
|
40
40
|
try {
|
|
41
|
-
const client = await createReadOnlyFileStoreBlobClient(storeUrl, metadata, log
|
|
41
|
+
const client = await createReadOnlyFileStoreBlobClient(storeUrl, metadata, log);
|
|
42
42
|
if (client) {
|
|
43
43
|
clients.push(client);
|
|
44
44
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/blob-client",
|
|
3
|
-
"version": "0.0.1-commit.
|
|
3
|
+
"version": "0.0.1-commit.a89ec08",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": "./dest/client/bin/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -56,12 +56,12 @@
|
|
|
56
56
|
]
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@aztec/blob-lib": "0.0.1-commit.
|
|
60
|
-
"@aztec/ethereum": "0.0.1-commit.
|
|
61
|
-
"@aztec/foundation": "0.0.1-commit.
|
|
62
|
-
"@aztec/kv-store": "0.0.1-commit.
|
|
63
|
-
"@aztec/stdlib": "0.0.1-commit.
|
|
64
|
-
"@aztec/telemetry-client": "0.0.1-commit.
|
|
59
|
+
"@aztec/blob-lib": "0.0.1-commit.a89ec08",
|
|
60
|
+
"@aztec/ethereum": "0.0.1-commit.a89ec08",
|
|
61
|
+
"@aztec/foundation": "0.0.1-commit.a89ec08",
|
|
62
|
+
"@aztec/kv-store": "0.0.1-commit.a89ec08",
|
|
63
|
+
"@aztec/stdlib": "0.0.1-commit.a89ec08",
|
|
64
|
+
"@aztec/telemetry-client": "0.0.1-commit.a89ec08",
|
|
65
65
|
"express": "^4.21.2",
|
|
66
66
|
"snappy": "^7.2.2",
|
|
67
67
|
"source-map-support": "^0.5.21",
|