Skip to content

Commit 629aa2a

Browse files
authored
chore: Blob and archiver syncing improvements (#13542)
This PR includes multiple chores/fixes, each split by commit: - **[Blob sink server fetches from L1 consensus on blob miss](87569ae175e55dc4bed6ada826d71aa6c2507069)**: The blob sink server, when it was requested a blob it didn't have, would fall back to an archival service (like blobscan) to retrieve it. Now, before falling back to blobscan, it tries with a configured L1 consensus client. This commit includes a refactor of the sink server so it just reuses code from the client, rather than reimplementing much of its logic. ``` [16:18:18.964] TRACE: blob-sink Received blobs request for block 0x29ca78726c02ddb3dc392c915efcccc9963744fe0b6838e9034022fca287adb9 {"blockId":"0x29ca78726c02ddb3dc392c915efcccc9963744fe0b6838e9034022fca287adb9"} [16:18:18.965] TRACE: blob-sink-client Attempting to get slot number for block hash {"l1ConsensusHostUrls":["https://lb.drpc.org/rest/KEY/eth-beacon-chain-sepolia"],"blockHash":"0x29ca78726c02ddb3dc392c915efcccc9963744fe0b6838e9034022fca287adb9","blobHashes":[]} [16:18:20.014] DEBUG: blob-sink-client Got slot number 7409506 from consensus host for querying blobs {"l1ConsensusHostUrls":["https://lb.drpc.org/rest/KEY/eth-beacon-chain-sepolia"],"blockHash":"0x29ca78726c02ddb3dc392c915efcccc9963744fe0b6838e9034022fca287adb9","blobHashes":[]} [16:18:20.014] TRACE: blob-sink-client Attempting to get blobs from consensus host {"slotNumber":7409506,"l1ConsensusHostUrl":"https://lb.drpc.org/rest/KEY/eth-beacon-chain-sepolia","blockHash":"0x29ca78726c02ddb3dc392c915efcccc9963744fe0b6838e9034022fca287adb9","blobHashes":[]} [16:18:20.014] DEBUG: blob-sink-client Fetching blob sidecar for 7409506 {"url":"https://lb.drpc.org/rest/KEY/eth-beacon-chain-sepolia/eth/v1/beacon/blob_sidecars/7409506"} [16:18:20.337] TRACE: blob-sink-client Failed to deserialise blob {"commitment":"0x84d99a55b6d1020fa0e3c9f912355dc5e6a1ec3e8001bd077e60c8abeb86fa5f8d68a19e1d22de899ce3102ceffbec37"} [16:18:20.337] TRACE: blob-sink-client Failed to deserialise blob {"commitment":"0xaa95e1d4f7c0bbaee7b8b81300b039164d9cadf9a0cc965efe7ecfbf0cf5fe583bc31058967241e43cf900f038080d7b"} [16:18:20.342] DEBUG: blob-sink-client Got 1 blobs from consensus host {"slotNumber":7409506,"l1ConsensusHostUrl":"https://lb.drpc.org/rest/KEY/eth-beacon-chain-sepolia","blockHash":"0x29ca78726c02ddb3dc392c915efcccc9963744fe0b6838e9034022fca287adb9","blobHashes":[]} [16:18:20.342] VERBOSE: blob-sink Storing blob downloaded from archive for block 0x29ca78726c02ddb3dc392c915efcccc9963744fe0b6838e9034022fca287adb9 [16:18:20.342] DEBUG: blob-sink Returning 1 blobs for block 0x29ca78726c02ddb3dc392c915efcccc9963744fe0b6838e9034022fca287adb9 {"blockId":"0x29ca78726c02ddb3dc392c915efcccc9963744fe0b6838e9034022fca287adb9"} ``` - **[Fix default paths to archive API](529bbf25325143786cc100580dd7f613d33ac72b)**: They were missing the protocol, which caused them to fail when doing `new URL(url)` in the telemetry setup. - **[Tweak logging for blob sink client](dea449f19a09538681336884ff86457cedc18c85)**: Updated logging so errors to fetch blobs are properly logged as warns, and retries are demoted to debug. ``` [16:16:27.287] DEBUG: blob-sink-client Fetching blob sidecar for 0xe79d762e7fdb5171a1d5a1d35e67f253eb409f07597a3a89b4cf17af5706601b {"url":"http://localhost:8090/eth/v1/beacon/blob_sidecars/0xe79d762e7fdb5171a1d5a1d35e67f253eb409f07597a3a89b4cf17af5706601b"} [16:16:27.288] DEBUG: blob-sink-client Fetching http://localhost:8090/eth/v1/beacon/blob_sidecars/0xe79d762e7fdb5171a1d5a1d35e67f253eb409f07597a3a89b4cf17af5706601b failed. Will retry in 1s... [16:16:28.290] DEBUG: blob-sink-client Fetching http://localhost:8090/eth/v1/beacon/blob_sidecars/0xe79d762e7fdb5171a1d5a1d35e67f253eb409f07597a3a89b4cf17af5706601b failed. Will retry in 1s... [16:16:29.291] DEBUG: blob-sink-client Fetching http://localhost:8090/eth/v1/beacon/blob_sidecars/0xe79d762e7fdb5171a1d5a1d35e67f253eb409f07597a3a89b4cf17af5706601b failed. Will retry in 3s... [16:16:32.292] WARN: blob-sink-client Error getting blob sidecar from http://localhost:8090: fetch failed [16:16:32.292] DEBUG: blob-sink-client Got 0 blobs from blob sink {"blobSinkUrl":"http://localhost:8090","blockHash":"0xe79d762e7fdb5171a1d5a1d35e67f253eb409f07597a3a89b4cf17af5706601b","blobHashes":["0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014"]} [16:16:32.292] WARN: blob-sink-client Failed to fetch blobs for 0xe79d762e7fdb5171a1d5a1d35e67f253eb409f07597a3a89b4cf17af5706601b from all blob sources {"blobSinkUrl":"http://localhost:8090","l1ConsensusHostUrls":[]} ``` - **[Do not finish archiver sync until success](dd851c7c8a8a02eadaf036669c6b904f6e81c94d)**: If there was an error during archiver syncing, the initial `createAndSync` promise would still resolve, and the node would start in a state of incomplete sync. Now the archiver waits until the sync is successful before returning control. ``` [16:16:12.116] INFO: archiver Starting archiver sync to rollup contract 0x2a6eb8e6110ad8e6cc0ba5b8a794740e05ce62a6 from L1 block 8076568 to current L1 block 8118693 [16:16:26.908] DEBUG: archiver Got 1 L2 block processed logs for L2 blocks 1-1 between L1 blocks 8077379-8077388 [16:16:27.287] DEBUG: blob-sink-client Fetching blob sidecar for 0xe79d762e7fdb5171a1d5a1d35e67f253eb409f07597a3a89b4cf17af5706601b {"url":"http://localhost:8090/eth/v1/beacon/blob_sidecars/0xe79d762e7fdb5171a1d5a1d35e67f253eb409f07597a3a89b4cf17af5706601b"} [16:16:27.288] DEBUG: blob-sink-client Fetching http://localhost:8090/eth/v1/beacon/blob_sidecars/0xe79d762e7fdb5171a1d5a1d35e67f253eb409f07597a3a89b4cf17af5706601b failed. Will retry in 1s... [16:16:28.290] DEBUG: blob-sink-client Fetching http://localhost:8090/eth/v1/beacon/blob_sidecars/0xe79d762e7fdb5171a1d5a1d35e67f253eb409f07597a3a89b4cf17af5706601b failed. Will retry in 1s... [16:16:29.291] DEBUG: blob-sink-client Fetching http://localhost:8090/eth/v1/beacon/blob_sidecars/0xe79d762e7fdb5171a1d5a1d35e67f253eb409f07597a3a89b4cf17af5706601b failed. Will retry in 3s... [16:16:32.292] WARN: blob-sink-client Error getting blob sidecar from http://localhost:8090: fetch failed [16:16:32.292] DEBUG: blob-sink-client Got 0 blobs from blob sink {"blobSinkUrl":"http://localhost:8090","blockHash":"0xe79d762e7fdb5171a1d5a1d35e67f253eb409f07597a3a89b4cf17af5706601b","blobHashes":["0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014"]} [16:16:32.292] WARN: blob-sink-client Failed to fetch blobs for 0xe79d762e7fdb5171a1d5a1d35e67f253eb409f07597a3a89b4cf17af5706601b from all blob sources {"blobSinkUrl":"http://localhost:8090","l1ConsensusHostUrls":[]} [16:16:32.292] ERROR: archiver Error syncing archiver: No blob bodies found for block 1 [16:16:32.292] INFO: archiver Retrying initial archiver sync in 500ms [16:16:32.957] INFO: archiver Starting archiver sync to rollup contract 0x2a6eb8e6110ad8e6cc0ba5b8a794740e05ce62a6 from L1 block 8076568 to current L1 block 8118695 ``` - **[Fix start --archiver command](56b426dd8a02cc2d1ef2ae03c5303c7399255e47)**: Wrong config mappings meant that the archiver was only fetching the rollup contract address from config, and now the registry contract address is the one required. - **[Test blob sources on archiver startup](cef04b78f2fb7f878cc7b4134085ccf96dc1cb4e)**: Reaches out to every L1 consensus host configured, blob sink, and archive blob service on archiver startup, and logs the result. ``` [16:22:32.054] INFO: blob-sink-client Testing configured blob sources {"blobSinkUrl":"http://localhost:8090","l1ConsensusHostUrls":["https://lb.drpc.org/rest/KEY/eth-beacon-chain-sepolia"],"archiveUrl":"api.sepolia.blobscan.com"} [16:22:32.059] INFO: blob-sink-client Blob sink is reachable {"blobSinkUrl":"http://localhost:8090"} [16:22:32.584] INFO: blob-sink-client L1 consensus host is reachable {"l1ConsensusHostUrl":"https://lb.drpc.org/rest/KEY/eth-beacon-chain-sepolia"} [16:22:35.155] INFO: blob-sink-client Archive client is reachable and synced to L1 block 8088445 {"latest":{"hash":"0x80c3dd67e5d296b3faa880381a17936bc259b33764e5f6c05ab1492c1846785c","slot":7377108,"number":8088445},"archiveUrl":"api.sepolia.blobscan.com"} [16:22:35.322] INFO: archiver Starting archiver sync to rollup contract 0x2a6eb8e6110ad8e6cc0ba5b8a794740e05ce62a6 from L1 block 8076568 to current L1 block 8118721 ``` Fixes #13530
1 parent 2f9458a commit 629aa2a

File tree

29 files changed

+317
-183
lines changed

29 files changed

+317
-183
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Blob } from '@aztec/blob-lib';
22
import type { BlobSinkClientInterface } from '@aztec/blob-sink/client';
3+
import { BlobWithIndex } from '@aztec/blob-sink/types';
34
import { GENESIS_ARCHIVE_ROOT } from '@aztec/constants';
45
import { DefaultL1ContractsConfig, RollupContract, type ViemPublicClient } from '@aztec/ethereum';
56
import { EthAddress } from '@aztec/foundation/eth-address';
@@ -640,5 +641,6 @@ async function makeVersionedBlobHashes(l2Block: L2Block): Promise<`0x${string}`[
640641
* @returns The blobs.
641642
*/
642643
async function makeBlobsFromBlock(block: L2Block) {
643-
return await Blob.getBlobs(block.body.toBlobFields());
644+
const blobs = await Blob.getBlobs(block.body.toBlobFields());
645+
return blobs.map((blob, index) => new BlobWithIndex(blob, index));
644646
}

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { EthAddress } from '@aztec/foundation/eth-address';
44
import { Fr } from '@aztec/foundation/fields';
55
import { type Logger, createLogger } from '@aztec/foundation/log';
66
import { RunningPromise, makeLoggingErrorHandler } from '@aztec/foundation/running-promise';
7+
import { sleep } from '@aztec/foundation/sleep';
78
import { count } from '@aztec/foundation/string';
89
import { elapsed } from '@aztec/foundation/timer';
910
import { InboxAbi } from '@aztec/l1-artifacts';
@@ -182,8 +183,13 @@ export class Archiver extends EventEmitter implements ArchiveSource, Traceable {
182183
throw new Error('Archiver is already running');
183184
}
184185

186+
await this.blobSinkClient.testSources();
187+
185188
if (blockUntilSynced) {
186-
await this.syncSafe(blockUntilSynced);
189+
while (!(await this.syncSafe(true))) {
190+
this.log.info(`Retrying initial archiver sync in ${this.config.pollingIntervalMs}ms`);
191+
await sleep(this.config.pollingIntervalMs);
192+
}
187193
}
188194

189195
this.runningPromise = new RunningPromise(
@@ -211,8 +217,14 @@ export class Archiver extends EventEmitter implements ArchiveSource, Traceable {
211217
private async syncSafe(initialRun: boolean) {
212218
try {
213219
await this.sync(initialRun);
220+
return true;
214221
} catch (error) {
215-
this.log.error('Error during sync', { error });
222+
if (error instanceof NoBlobBodiesFoundError) {
223+
this.log.error(`Error syncing archiver: ${error.message}`);
224+
} else {
225+
this.log.error('Error during archiver sync', error);
226+
}
227+
return false;
216228
}
217229
}
218230

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
type L1ContractAddresses,
44
type L1ContractsConfig,
55
type L1ReaderConfig,
6+
l1ContractAddressesMapping,
67
l1ContractsConfigMappings,
78
l1ReaderConfigMappings,
89
} from '@aztec/ethereum';
@@ -88,6 +89,10 @@ export const archiverConfigMappings: ConfigMappingsType<ArchiverConfig> = {
8889
...numberConfigHelper(1000),
8990
},
9091
...l1ContractsConfigMappings,
92+
l1Contracts: {
93+
description: 'The deployed L1 contract addresses',
94+
nested: l1ContractAddressesMapping,
95+
},
9196
};
9297

9398
/**

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ async function getBlockFromRollupTx(
248248

249249
let blockFields: Fr[];
250250
try {
251-
blockFields = Blob.toEncodedFields(blobBodies);
251+
blockFields = Blob.toEncodedFields(blobBodies.map(b => b.blob));
252252
} catch (err: any) {
253253
if (err instanceof BlobDeserializationError) {
254254
logger.fatal(err.message);

yarn-project/aztec-node/src/aztec-node/server.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,8 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
165165
const telemetry = deps.telemetry ?? getTelemetryClient();
166166
const log = deps.logger ?? createLogger('node');
167167
const dateProvider = deps.dateProvider ?? new DateProvider();
168-
const blobSinkClient = deps.blobSinkClient ?? createBlobSinkClient(config);
168+
const blobSinkClient =
169+
deps.blobSinkClient ?? createBlobSinkClient(config, { logger: createLogger('node:blob-sink:client') });
169170
const ethereumChain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
170171

171172
// validate that the actual chain id matches that specified in configuration

yarn-project/aztec/src/cli/cmds/start_archiver.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,9 @@ import {
66
getArchiverConfigFromEnv,
77
} from '@aztec/archiver';
88
import { createLogger } from '@aztec/aztec.js';
9-
import {
10-
type BlobSinkConfig,
11-
blobSinkConfigMapping,
12-
createBlobSinkClient,
13-
getBlobSinkConfigFromEnv,
14-
} from '@aztec/blob-sink/client';
9+
import { type BlobSinkConfig, blobSinkConfigMapping, createBlobSinkClient } from '@aztec/blob-sink/client';
1510
import type { NamespacedApiHandlers } from '@aztec/foundation/json-rpc/server';
16-
import { type DataStoreConfig, dataConfigMappings, getDataConfigFromEnv } from '@aztec/kv-store/config';
11+
import { type DataStoreConfig, dataConfigMappings } from '@aztec/kv-store/config';
1712
import { createStore } from '@aztec/kv-store/lmdb-v2';
1813
import { ArchiverApiSchema } from '@aztec/stdlib/interfaces/server';
1914
import { getConfigEnvVars as getTelemetryClientConfig, initTelemetryClient } from '@aztec/telemetry-client';
@@ -29,7 +24,7 @@ export async function startArchiver(
2924
signalHandlers: (() => Promise<void>)[],
3025
services: NamespacedApiHandlers,
3126
): Promise<{ config: ArchiverConfig & DataStoreConfig }> {
32-
const envConfig = { ...getArchiverConfigFromEnv(), ...getDataConfigFromEnv(), ...getBlobSinkConfigFromEnv() };
27+
const envConfig = getArchiverConfigFromEnv();
3328
const cliOptions = extractRelevantOptions<ArchiverConfig & DataStoreConfig & BlobSinkConfig>(
3429
options,
3530
{ ...archiverConfigMappings, ...dataConfigMappings, ...blobSinkConfigMapping },
@@ -57,7 +52,7 @@ export async function startArchiver(
5752
const archiverStore = new KVArchiverDataStore(store, archiverConfig.maxLogs);
5853

5954
const telemetry = initTelemetryClient(getTelemetryClientConfig());
60-
const blobSinkClient = createBlobSinkClient(archiverConfig);
55+
const blobSinkClient = createBlobSinkClient(archiverConfig, { logger: createLogger('archiver:blob-sink:client') });
6156
const archiver = await Archiver.createAndSync(archiverConfig, archiverStore, { telemetry, blobSinkClient }, true);
6257
services.archiver = [archiver, ArchiverApiSchema];
6358
signalHandlers.push(archiver.stop);

yarn-project/blob-lib/src/blob.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,16 +140,16 @@ describe('blob', () => {
140140
}
141141
});
142142

143-
it('Should serialise and deserialise a blob', async () => {
143+
it('should serialise and deserialise a blob', async () => {
144144
const blob = await Blob.fromFields([Fr.random(), Fr.random(), Fr.random()]);
145145
const blobBuffer = blob.toBuffer();
146146
const deserialisedBlob = Blob.fromBuffer(blobBuffer);
147147
expect(blob.fieldsHash.equals(deserialisedBlob.fieldsHash)).toBe(true);
148148
});
149149

150-
it('Should create a blob from a JSON object', async () => {
150+
it('should create a blob from a JSON object', async () => {
151151
const blob = await makeEncodedBlob(3);
152-
const blobJson = blob.toJson();
152+
const blobJson = blob.toJson(1);
153153
const deserialisedBlob = await Blob.fromJson(blobJson);
154154
expect(blob.fieldsHash.equals(deserialisedBlob.fieldsHash)).toBe(true);
155155
});

yarn-project/blob-lib/src/blob.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,10 @@ export class Blob {
123123
* @param index - optional - The index of the blob in the block.
124124
* @returns The JSON representation of the blob.
125125
*/
126-
toJson(index?: number): BlobJson {
126+
toJson(index: number): BlobJson {
127127
return {
128128
blob: `0x${Buffer.from(this.data).toString('hex')}`,
129-
index,
129+
index: index.toString(),
130130
// eslint-disable-next-line camelcase
131131
kzg_commitment: `0x${this.commitment.toString('hex')}`,
132132
// eslint-disable-next-line camelcase

yarn-project/blob-lib/src/interface.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44
export interface BlobJson {
55
blob: string;
6-
index?: number;
6+
index: string;
77
// eslint-disable-next-line camelcase
88
kzg_commitment: string;
99
// eslint-disable-next-line camelcase

yarn-project/blob-sink/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"exports": {
99
"./server": "./dest/server/index.js",
1010
"./client": "./dest/client/index.js",
11-
"./encoding": "./dest/encoding/index.js"
11+
"./encoding": "./dest/encoding/index.js",
12+
"./types": "./dest/types/index.js"
1213
},
1314
"inherits": [
1415
"../package.common.json"

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

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,30 @@ export const BlobscanBlockResponseSchema = z
3131
),
3232
})
3333
.transform(data =>
34-
data.transactions.flatMap(tx =>
35-
tx.blobs.map(blob => ({
36-
blob: blob.data,
37-
// eslint-disable-next-line camelcase
38-
kzg_commitment: blob.commitment,
39-
// eslint-disable-next-line camelcase
40-
kzg_proof: blob.proof,
41-
})),
42-
),
34+
data.transactions
35+
.flatMap(tx =>
36+
tx.blobs.map(blob => ({
37+
blob: blob.data,
38+
// eslint-disable-next-line camelcase
39+
kzg_commitment: blob.commitment,
40+
// eslint-disable-next-line camelcase
41+
kzg_proof: blob.proof,
42+
})),
43+
)
44+
.map((blob, index) => ({ ...blob, index: index.toString() })),
4345
) satisfies ZodFor<BlobJson[]>;
4446

47+
// Response from https://api.blobscan.com/blocks?sort=desc&type=canonical
48+
export const BlobscanBlocksResponseSchema = z.object({
49+
blocks: z.array(
50+
z.object({
51+
hash: z.string(),
52+
slot: z.number().int(),
53+
number: z.number().int(),
54+
}),
55+
),
56+
});
57+
4558
export class BlobscanArchiveClient implements BlobArchiveClient {
4659
private readonly logger = createLogger('blob-sink:blobscan-archive-client');
4760
private readonly fetchOpts = { headers: { accept: 'application/json' } };
@@ -68,6 +81,30 @@ export class BlobscanArchiveClient implements BlobArchiveClient {
6881
);
6982
}
7083

84+
public async getLatestBlock(): Promise<{ hash: string; number: number; slot: number }> {
85+
const url = `https://${this.baseUrl}/blocks?sort=desc&type=canonical&p=1&ps=1`;
86+
this.logger.trace(`Fetching latest block from ${url}`);
87+
const response = await this.fetch(url, this.fetchOpts);
88+
89+
if (response.status !== 200) {
90+
throw new Error(`Failed to fetch latest block: ${response.statusText} (${response.status})`, {
91+
cause: {
92+
httpResponse: {
93+
status: response.status,
94+
body: await response.text().catch(() => 'Failed to read response body'),
95+
},
96+
},
97+
});
98+
}
99+
100+
const parsed = await response.json().then((data: any) => BlobscanBlocksResponseSchema.parse(data));
101+
if (parsed.blocks.length === 0) {
102+
throw new Error(`No blocks found at ${this.baseUrl}`);
103+
}
104+
105+
return parsed.blocks[0];
106+
}
107+
71108
public getBaseUrl(): string {
72109
return this.baseUrl;
73110
}
@@ -87,10 +124,7 @@ export class BlobscanArchiveClient implements BlobArchiveClient {
87124
cause: {
88125
httpResponse: {
89126
status: response.status,
90-
body: await response.text().catch(err => {
91-
this.logger.warn('Failed to read response body', err);
92-
return '';
93-
}),
127+
body: await response.text().catch(() => 'Failed to read response body'),
94128
},
95129
},
96130
});

yarn-project/blob-sink/src/archive/factory.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ export function createBlobArchiveClient(config: BlobSinkConfig): BlobArchiveClie
88
}
99

1010
if (config.l1ChainId === 1) {
11-
return new BlobscanArchiveClient('api.blobscan.com');
11+
return new BlobscanArchiveClient('https://api.blobscan.com');
1212
} else if (config.l1ChainId === 11155111) {
13-
return new BlobscanArchiveClient('api.sepolia.blobscan.com');
13+
return new BlobscanArchiveClient('https://api.sepolia.blobscan.com');
1414
}
1515

1616
return undefined;

yarn-project/blob-sink/src/archive/interface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ import type { BlobJson } from '@aztec/blob-lib';
44
export interface BlobArchiveClient {
55
getBlobData(id: string): Promise<Buffer | undefined>;
66
getBlobsFromBlock(blockId: string): Promise<BlobJson[] | undefined>;
7+
getLatestBlock(): Promise<{ hash: string; number: number; slot: number }>;
78
getBaseUrl(): string;
89
}

yarn-project/blob-sink/src/client/bin/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ async function main() {
2424
const blobs = await blobSinkClient.getBlobSidecar(blockHash, blobHashes);
2525
logger.info(`Got ${blobs.length} blobs`);
2626
for (const blob of blobs) {
27-
console.log(blob.toJson());
27+
console.log(blob.toJSON());
2828
}
2929
}
3030

yarn-project/blob-sink/src/client/blob-sink-client-tests.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ export function runBlobSinkClientTests(
3333

3434
const retrievedBlobs = await client.getBlobSidecar(blockId, [blobHash]);
3535
expect(retrievedBlobs).toHaveLength(1);
36-
expect(retrievedBlobs[0].fieldsHash.toString()).toBe(blob.fieldsHash.toString());
37-
expect(retrievedBlobs[0].commitment.toString('hex')).toBe(blob.commitment.toString('hex'));
36+
expect(retrievedBlobs[0].blob.fieldsHash.toString()).toBe(blob.fieldsHash.toString());
37+
expect(retrievedBlobs[0].blob.commitment.toString('hex')).toBe(blob.commitment.toString('hex'));
3838
});
3939

4040
it('should handle multiple blobs', async () => {
@@ -49,15 +49,15 @@ export function runBlobSinkClientTests(
4949
expect(retrievedBlobs).toHaveLength(3);
5050

5151
for (let i = 0; i < blobs.length; i++) {
52-
expect(retrievedBlobs[i].fieldsHash.toString()).toBe(blobs[i].fieldsHash.toString());
53-
expect(retrievedBlobs[i].commitment.toString('hex')).toBe(blobs[i].commitment.toString('hex'));
52+
expect(retrievedBlobs[i].blob.fieldsHash.toString()).toBe(blobs[i].fieldsHash.toString());
53+
expect(retrievedBlobs[i].blob.commitment.toString('hex')).toBe(blobs[i].commitment.toString('hex'));
5454
}
5555

5656
// Can request blobs by index
5757
const retrievedBlobsByIndex = await client.getBlobSidecar(blockId, blobHashes, [0, 2]);
5858
expect(retrievedBlobsByIndex).toHaveLength(2);
59-
expect(retrievedBlobsByIndex[0].fieldsHash.toString()).toBe(blobs[0].fieldsHash.toString());
60-
expect(retrievedBlobsByIndex[1].fieldsHash.toString()).toBe(blobs[2].fieldsHash.toString());
59+
expect(retrievedBlobsByIndex[0].blob.fieldsHash.toString()).toBe(blobs[0].fieldsHash.toString());
60+
expect(retrievedBlobsByIndex[1].blob.fieldsHash.toString()).toBe(blobs[2].fieldsHash.toString());
6161
});
6262

6363
it('should return empty array for non-existent block', async () => {

yarn-project/blob-sink/src/client/config.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,10 @@ export const blobSinkConfigMapping: ConfigMappingsType<BlobSinkConfig> = {
6969
export function getBlobSinkConfigFromEnv(): BlobSinkConfig {
7070
return getConfigFromMappings<BlobSinkConfig>(blobSinkConfigMapping);
7171
}
72+
73+
/**
74+
* Returns whether the given blob sink config has any remote sources defined.
75+
*/
76+
export function hasRemoteBlobSinkSources(config: BlobSinkConfig = {}): boolean {
77+
return !!(config.blobSinkUrl || config.l1ConsensusHostUrls?.length || config.archiveApiUrl);
78+
}
Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
1+
import { type Logger, createLogger } from '@aztec/foundation/log';
2+
13
import { MemoryBlobStore } from '../blobstore/memory_blob_store.js';
2-
import type { BlobSinkConfig } from './config.js';
4+
import { type BlobSinkConfig, hasRemoteBlobSinkSources } from './config.js';
35
import { HttpBlobSinkClient } from './http.js';
46
import type { BlobSinkClientInterface } from './interface.js';
57
import { LocalBlobSinkClient } from './local.js';
68

7-
export function createBlobSinkClient(config?: BlobSinkConfig): BlobSinkClientInterface {
8-
if (
9-
!config?.blobSinkUrl &&
10-
(!config?.l1ConsensusHostUrls || config?.l1ConsensusHostUrls?.length == 0) &&
11-
!config?.archiveApiUrl
12-
) {
9+
export function createBlobSinkClient(config?: BlobSinkConfig, deps?: { logger: Logger }): BlobSinkClientInterface {
10+
const log = deps?.logger ?? createLogger('blob-sink:client');
11+
if (!hasRemoteBlobSinkSources(config)) {
12+
log.info(`Creating local blob sink client.`);
1313
const blobStore = new MemoryBlobStore();
1414
return new LocalBlobSinkClient(blobStore);
1515
}
1616

17-
return new HttpBlobSinkClient(config);
17+
log.info(`Creating HTTP blob sink client.`, {
18+
blobSinkUrl: config?.blobSinkUrl,
19+
l1ConsensusHostUrls: config?.l1ConsensusHostUrls,
20+
archiveApiUrl: config?.archiveApiUrl,
21+
});
22+
return new HttpBlobSinkClient(config, deps);
1823
}

0 commit comments

Comments
 (0)