@aztec/blob-client 0.0.1-commit.ec5f612 → 0.0.1-commit.ec7ac5448

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.
@@ -40,6 +40,12 @@ export interface BlobClientConfig extends BlobArchiveApiConfig {
40
40
  * Interval in minutes for uploading healthcheck file to file store (default: 60 = 1 hour)
41
41
  */
42
42
  blobHealthcheckUploadIntervalMinutes?: number;
43
+ /** Timeout for HTTP requests to the L1 RPC node in ms. */
44
+ l1HttpTimeoutMS?: number;
45
+ /** Whether to prefer filestores over consensus clients when fetching blobs. Default: false (consensus first). */
46
+ blobPreferFilestores?: boolean;
47
+ /** Timeout in ms for HTTP requests to the blob file store. Default: 10000 (10s). */
48
+ blobFileStoreTimeoutMs?: number;
43
49
  }
44
50
  export declare const blobClientConfigMapping: ConfigMappingsType<BlobClientConfig>;
45
51
  /**
@@ -51,4 +57,4 @@ export declare function getBlobClientConfigFromEnv(): BlobClientConfig;
51
57
  * Returns whether the given blob client config has any remote sources defined.
52
58
  */
53
59
  export declare function hasRemoteBlobSources(config?: BlobClientConfig): boolean;
54
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY2xpZW50L2NvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsS0FBSyxrQkFBa0IsRUFDdkIsV0FBVyxFQUdaLE1BQU0sMEJBQTBCLENBQUM7QUFFbEMsT0FBTyxFQUFFLEtBQUssb0JBQW9CLEVBQWdDLE1BQU0sc0JBQXNCLENBQUM7QUFFL0Y7O0dBRUc7QUFDSCxNQUFNLFdBQVcsZ0JBQWlCLFNBQVEsb0JBQW9CO0lBQzVEOztPQUVHO0lBQ0gsU0FBUyxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUM7SUFFckI7O09BRUc7SUFDSCxtQkFBbUIsQ0FBQyxFQUFFLE1BQU0sRUFBRSxDQUFDO0lBRS9COztPQUVHO0lBQ0gsc0JBQXNCLENBQUMsRUFBRSxXQUFXLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztJQUUvQzs7T0FFRztJQUNILDRCQUE0QixDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUM7SUFFeEM7O09BRUc7SUFDSCxpQkFBaUIsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUUzQjs7T0FFRztJQUNILHFCQUFxQixDQUFDLEVBQUUsT0FBTyxDQUFDO0lBRWhDOztPQUVHO0lBQ0gsaUJBQWlCLENBQUMsRUFBRSxNQUFNLEVBQUUsQ0FBQztJQUU3Qjs7T0FFRztJQUNILHNCQUFzQixDQUFDLEVBQUUsTUFBTSxDQUFDO0lBRWhDOztPQUVHO0lBQ0gsb0NBQW9DLENBQUMsRUFBRSxNQUFNLENBQUM7Q0FDL0M7QUFFRCxlQUFPLE1BQU0sdUJBQXVCLEVBQUUsa0JBQWtCLENBQUMsZ0JBQWdCLENBb0R4RSxDQUFDO0FBRUY7OztHQUdHO0FBQ0gsd0JBQWdCLDBCQUEwQixJQUFJLGdCQUFnQixDQUU3RDtBQUVEOztHQUVHO0FBQ0gsd0JBQWdCLG9CQUFvQixDQUFDLE1BQU0sR0FBRSxnQkFBcUIsR0FBRyxPQUFPLENBRTNFIn0=
60
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY2xpZW50L2NvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsS0FBSyxrQkFBa0IsRUFDdkIsV0FBVyxFQUlaLE1BQU0sMEJBQTBCLENBQUM7QUFFbEMsT0FBTyxFQUFFLEtBQUssb0JBQW9CLEVBQWdDLE1BQU0sc0JBQXNCLENBQUM7QUFFL0Y7O0dBRUc7QUFDSCxNQUFNLFdBQVcsZ0JBQWlCLFNBQVEsb0JBQW9CO0lBQzVEOztPQUVHO0lBQ0gsU0FBUyxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUM7SUFFckI7O09BRUc7SUFDSCxtQkFBbUIsQ0FBQyxFQUFFLE1BQU0sRUFBRSxDQUFDO0lBRS9COztPQUVHO0lBQ0gsc0JBQXNCLENBQUMsRUFBRSxXQUFXLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztJQUUvQzs7T0FFRztJQUNILDRCQUE0QixDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUM7SUFFeEM7O09BRUc7SUFDSCxpQkFBaUIsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUUzQjs7T0FFRztJQUNILHFCQUFxQixDQUFDLEVBQUUsT0FBTyxDQUFDO0lBRWhDOztPQUVHO0lBQ0gsaUJBQWlCLENBQUMsRUFBRSxNQUFNLEVBQUUsQ0FBQztJQUU3Qjs7T0FFRztJQUNILHNCQUFzQixDQUFDLEVBQUUsTUFBTSxDQUFDO0lBRWhDOztPQUVHO0lBQ0gsb0NBQW9DLENBQUMsRUFBRSxNQUFNLENBQUM7SUFFOUMsMERBQTBEO0lBQzFELGVBQWUsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUV6QixpSEFBaUg7SUFDakgsb0JBQW9CLENBQUMsRUFBRSxPQUFPLENBQUM7SUFFL0Isb0ZBQW9GO0lBQ3BGLHNCQUFzQixDQUFDLEVBQUUsTUFBTSxDQUFDO0NBQ2pDO0FBRUQsZUFBTyxNQUFNLHVCQUF1QixFQUFFLGtCQUFrQixDQUFDLGdCQUFnQixDQW1FeEUsQ0FBQztBQUVGOzs7R0FHRztBQUNILHdCQUFnQiwwQkFBMEIsSUFBSSxnQkFBZ0IsQ0FFN0Q7QUFFRDs7R0FFRztBQUNILHdCQUFnQixvQkFBb0IsQ0FBQyxNQUFNLEdBQUUsZ0JBQXFCLEdBQUcsT0FBTyxDQUUzRSJ9
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/client/config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EACvB,WAAW,EAGZ,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,KAAK,oBAAoB,EAAgC,MAAM,sBAAsB,CAAC;AAE/F;;GAEG;AACH,MAAM,WAAW,gBAAiB,SAAQ,oBAAoB;IAC5D;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAErB;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE/B;;OAEG;IACH,sBAAsB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;IAE/C;;OAEG;IACH,4BAA4B,CAAC,EAAE,MAAM,EAAE,CAAC;IAExC;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAEhC;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE7B;;OAEG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAEhC;;OAEG;IACH,oCAAoC,CAAC,EAAE,MAAM,CAAC;CAC/C;AAED,eAAO,MAAM,uBAAuB,EAAE,kBAAkB,CAAC,gBAAgB,CAoDxE,CAAC;AAEF;;;GAGG;AACH,wBAAgB,0BAA0B,IAAI,gBAAgB,CAE7D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,gBAAqB,GAAG,OAAO,CAE3E"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/client/config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EACvB,WAAW,EAIZ,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,KAAK,oBAAoB,EAAgC,MAAM,sBAAsB,CAAC;AAE/F;;GAEG;AACH,MAAM,WAAW,gBAAiB,SAAQ,oBAAoB;IAC5D;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAErB;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE/B;;OAEG;IACH,sBAAsB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;IAE/C;;OAEG;IACH,4BAA4B,CAAC,EAAE,MAAM,EAAE,CAAC;IAExC;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAEhC;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE7B;;OAEG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAEhC;;OAEG;IACH,oCAAoC,CAAC,EAAE,MAAM,CAAC;IAE9C,0DAA0D;IAC1D,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,iHAAiH;IACjH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAE/B,oFAAoF;IACpF,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,eAAO,MAAM,uBAAuB,EAAE,kBAAkB,CAAC,gBAAgB,CAmExE,CAAC;AAEF;;;GAGG;AACH,wBAAgB,0BAA0B,IAAI,gBAAgB,CAE7D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,gBAAqB,GAAG,OAAO,CAE3E"}
@@ -1,4 +1,4 @@
1
- import { SecretValue, booleanConfigHelper, getConfigFromMappings } from '@aztec/foundation/config';
1
+ import { SecretValue, booleanConfigHelper, getConfigFromMappings, optionalNumberConfigHelper } from '@aztec/foundation/config';
2
2
  import { blobArchiveApiConfigMappings } from '../archive/config.js';
3
3
  export const blobClientConfigMapping = {
4
4
  l1RpcUrls: {
@@ -45,6 +45,21 @@ export const blobClientConfigMapping = {
45
45
  description: 'Interval in minutes for uploading healthcheck file to file store (default: 60 = 1 hour)',
46
46
  parseEnv: (val)=>val ? +val : undefined
47
47
  },
48
+ l1HttpTimeoutMS: {
49
+ env: 'ETHEREUM_HTTP_TIMEOUT_MS',
50
+ description: 'Timeout for HTTP requests to the L1 RPC node in ms.',
51
+ ...optionalNumberConfigHelper()
52
+ },
53
+ blobPreferFilestores: {
54
+ env: 'BLOB_PREFER_FILESTORES',
55
+ description: 'Whether to prefer filestores over consensus clients when fetching blobs. Default: false.',
56
+ ...booleanConfigHelper(false)
57
+ },
58
+ blobFileStoreTimeoutMs: {
59
+ env: 'BLOB_FILE_STORE_TIMEOUT_MS',
60
+ description: 'Timeout in ms for HTTP requests to the blob file store. Default: 10000 (10s).',
61
+ ...optionalNumberConfigHelper()
62
+ },
48
63
  ...blobArchiveApiConfigMappings
49
64
  };
50
65
  /**
@@ -37,4 +37,4 @@ export interface BlobClientWithFileStoresConfig extends BlobClientConfig {
37
37
  * @returns A BlobClientInterface configured with file store support, already started
38
38
  */
39
39
  export declare function createBlobClientWithFileStores(config: BlobClientWithFileStoresConfig, logger?: Logger): Promise<BlobClientInterface>;
40
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFjdG9yeS5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NsaWVudC9mYWN0b3J5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxLQUFLLE1BQU0sRUFBZ0IsTUFBTSx1QkFBdUIsQ0FBQztBQVFsRSxPQUFPLEtBQUssRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBQ2pGLE9BQU8sRUFBRSxLQUFLLGdCQUFnQixFQUF3QixNQUFNLGFBQWEsQ0FBQztBQUUxRSxPQUFPLEtBQUssRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRzFELE1BQU0sV0FBVyxvQkFBb0I7SUFDbkMsTUFBTSxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ2hCLDBDQUEwQztJQUMxQyxnQkFBZ0IsQ0FBQyxFQUFFLG1CQUFtQixFQUFFLENBQUM7SUFDekMsMkNBQTJDO0lBQzNDLHFCQUFxQixDQUFDLEVBQUUsbUJBQW1CLENBQUM7Q0FDN0M7QUFFRCx3QkFBZ0IsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLEVBQUUsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDLEVBQUUsb0JBQW9CLEdBQUcsbUJBQW1CLENBbUI1RztBQUVEOzs7R0FHRztBQUNILE1BQU0sV0FBVyw4QkFBK0IsU0FBUSxnQkFBZ0I7SUFDdEUsU0FBUyxFQUFFLE1BQU0sQ0FBQztJQUNsQixhQUFhLEVBQUUsTUFBTSxDQUFDO0lBQ3RCLFdBQVcsRUFBRTtRQUFFLGFBQWEsRUFBRTtZQUFFLFFBQVEsSUFBSSxNQUFNLENBQUE7U0FBRSxDQUFBO0tBQUUsQ0FBQztDQUN4RDtBQUVEOzs7Ozs7Ozs7Ozs7R0FZRztBQUNILHdCQUFzQiw4QkFBOEIsQ0FDbEQsTUFBTSxFQUFFLDhCQUE4QixFQUN0QyxNQUFNLENBQUMsRUFBRSxNQUFNLEdBQ2QsT0FBTyxDQUFDLG1CQUFtQixDQUFDLENBdUI5QiJ9
40
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFjdG9yeS5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NsaWVudC9mYWN0b3J5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxLQUFLLE1BQU0sRUFBZ0IsTUFBTSx1QkFBdUIsQ0FBQztBQVFsRSxPQUFPLEtBQUssRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBQ2pGLE9BQU8sRUFBRSxLQUFLLGdCQUFnQixFQUF3QixNQUFNLGFBQWEsQ0FBQztBQUUxRSxPQUFPLEtBQUssRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRzFELE1BQU0sV0FBVyxvQkFBb0I7SUFDbkMsTUFBTSxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ2hCLDBDQUEwQztJQUMxQyxnQkFBZ0IsQ0FBQyxFQUFFLG1CQUFtQixFQUFFLENBQUM7SUFDekMsMkNBQTJDO0lBQzNDLHFCQUFxQixDQUFDLEVBQUUsbUJBQW1CLENBQUM7Q0FDN0M7QUFFRCx3QkFBZ0IsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLEVBQUUsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDLEVBQUUsb0JBQW9CLEdBQUcsbUJBQW1CLENBbUI1RztBQUVEOzs7R0FHRztBQUNILE1BQU0sV0FBVyw4QkFBK0IsU0FBUSxnQkFBZ0I7SUFDdEUsU0FBUyxFQUFFLE1BQU0sQ0FBQztJQUNsQixhQUFhLEVBQUUsTUFBTSxDQUFDO0lBQ3RCLFdBQVcsRUFBRTtRQUFFLGFBQWEsRUFBRTtZQUFFLFFBQVEsSUFBSSxNQUFNLENBQUE7U0FBRSxDQUFBO0tBQUUsQ0FBQztDQUN4RDtBQUVEOzs7Ozs7Ozs7Ozs7R0FZRztBQUNILHdCQUFzQiw4QkFBOEIsQ0FDbEQsTUFBTSxFQUFFLDhCQUE4QixFQUN0QyxNQUFNLENBQUMsRUFBRSxNQUFNLEdBQ2QsT0FBTyxDQUFDLG1CQUFtQixDQUFDLENBOEI5QiJ9
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/client/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAQlE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AACjF,OAAO,EAAE,KAAK,gBAAgB,EAAwB,MAAM,aAAa,CAAC;AAE1E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG1D,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,gBAAgB,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACzC,2CAA2C;IAC3C,qBAAqB,CAAC,EAAE,mBAAmB,CAAC;CAC7C;AAED,wBAAgB,gBAAgB,CAAC,MAAM,CAAC,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE,oBAAoB,GAAG,mBAAmB,CAmB5G;AAED;;;GAGG;AACH,MAAM,WAAW,8BAA+B,SAAQ,gBAAgB;IACtE,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE;QAAE,aAAa,EAAE;YAAE,QAAQ,IAAI,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;CACxD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,8BAA8B,CAClD,MAAM,EAAE,8BAA8B,EACtC,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,mBAAmB,CAAC,CAuB9B"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/client/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAQlE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AACjF,OAAO,EAAE,KAAK,gBAAgB,EAAwB,MAAM,aAAa,CAAC;AAE1E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG1D,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,gBAAgB,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACzC,2CAA2C;IAC3C,qBAAqB,CAAC,EAAE,mBAAmB,CAAC;CAC7C;AAED,wBAAgB,gBAAgB,CAAC,MAAM,CAAC,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE,oBAAoB,GAAG,mBAAmB,CAmB5G;AAED;;;GAGG;AACH,MAAM,WAAW,8BAA+B,SAAQ,gBAAgB;IACtE,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE;QAAE,aAAa,EAAE;YAAE,QAAQ,IAAI,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;CACxD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,8BAA8B,CAClD,MAAM,EAAE,8BAA8B,EACtC,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,mBAAmB,CAAC,CA8B9B"}
@@ -42,8 +42,14 @@ export function createBlobClient(config, deps) {
42
42
  rollupVersion: config.rollupVersion,
43
43
  rollupAddress: config.l1Contracts.rollupAddress.toString()
44
44
  };
45
+ // Disable internal retries for blob file stores — retry logic is handled by HttpBlobClient.
46
+ // Set a configurable timeout (default 10s) to avoid hanging on slow stores.
47
+ const httpOptions = {
48
+ retryBackoff: [],
49
+ timeoutMs: config.blobFileStoreTimeoutMs ?? 10_000
50
+ };
45
51
  const [fileStoreClients, fileStoreUploadClient] = await Promise.all([
46
- createReadOnlyFileStoreBlobClients(config.blobFileStoreUrls, fileStoreMetadata, log),
52
+ createReadOnlyFileStoreBlobClients(config.blobFileStoreUrls, fileStoreMetadata, log, httpOptions),
47
53
  createWritableFileStoreBlobClient(config.blobFileStoreUploadUrl, fileStoreMetadata, log)
48
54
  ]);
49
55
  const client = createBlobClient(config, {
@@ -18,6 +18,8 @@ export declare class HttpBlobClient implements BlobClientInterface {
18
18
  private beaconGenesisTime?;
19
19
  /** Cached beacon slot duration in seconds. Fetched once at startup. */
20
20
  private beaconSecondsPerSlot?;
21
+ /** Indexes of consensus hosts that serve blob sidecars (supernodes). Populated by testSources(). */
22
+ private superNodeHostIndexes?;
21
23
  constructor(config?: BlobClientConfig, opts?: {
22
24
  logger?: Logger;
23
25
  archiveClient?: BlobArchiveClient;
@@ -41,21 +43,21 @@ export declare class HttpBlobClient implements BlobClientInterface {
41
43
  testSources(): Promise<void>;
42
44
  sendBlobsToFilestore(blobs: Blob[]): Promise<boolean>;
43
45
  /**
44
- * Get the blob sidecar
46
+ * Get the blob sidecar.
45
47
  *
46
- * If requesting from the blob client, we send the blobkHash
47
- * If requesting from the beacon node, we send the slot number
48
- *
49
- * Source ordering depends on sync state:
50
- * - Historical sync: blob client → FileStore → L1 consensus → Archive
51
- * - Near tip sync: blob client → FileStore → L1 consensus → FileStore (with retries) → Archive (eg blobscan)
48
+ * Alternates between two primary sources (consensus and filestore) in a retry loop,
49
+ * then falls back to archive if blobs are still missing. The order of the primary
50
+ * sources is configurable via `blobPreferFilestores`.
52
51
  *
53
52
  * @param blockHash - The block hash
54
53
  * @param blobHashes - The blob hashes to fetch
55
- * @param opts - Options including isHistoricalSync flag
54
+ * @param opts - Options for slot resolution
56
55
  * @returns The blobs
57
56
  */
58
57
  getBlobSidecar(blockHash: `0x${string}`, blobHashes: Buffer[], opts?: GetBlobSidecarOptions): Promise<Blob[]>;
58
+ /** Resolves the beacon slot number for the given block hash. Returns undefined if no consensus hosts. */
59
+ private resolveSlotNumber;
60
+ private tryConsensusHosts;
59
61
  private tryFileStores;
60
62
  getBlobSidecarFrom(hostUrl: string, blockHashOrSlot: string | number, blobHashes?: Buffer[], l1ConsensusHostIndex?: number): Promise<Blob[]>;
61
63
  getBlobsFromHost(hostUrl: string, blockHashOrSlot: string | number, l1ConsensusHostIndex?: number, blobHashes?: Buffer[]): Promise<BlobJson[]>;
@@ -82,4 +84,4 @@ export declare class HttpBlobClient implements BlobClientInterface {
82
84
  */
83
85
  stop(): void;
84
86
  }
85
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NsaWVudC9odHRwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxJQUFJLEVBQUUsS0FBSyxRQUFRLEVBQStCLE1BQU0saUJBQWlCLENBQUM7QUFFbkYsT0FBTyxFQUFFLEtBQUssTUFBTSxFQUFnQixNQUFNLHVCQUF1QixDQUFDO0FBT2xFLE9BQU8sS0FBSyxFQUFFLGlCQUFpQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDakUsT0FBTyxLQUFLLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx1Q0FBdUMsQ0FBQztBQUVqRixPQUFPLEVBQUUsS0FBSyxnQkFBZ0IsRUFBOEIsTUFBTSxhQUFhLENBQUM7QUFDaEYsT0FBTyxLQUFLLEVBQUUsbUJBQW1CLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUVqRixxQkFBYSxjQUFlLFlBQVcsbUJBQW1CO0lBa0J0RCxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUk7SUFqQnZCLFNBQVMsQ0FBQyxRQUFRLENBQUMsR0FBRyxFQUFFLE1BQU0sQ0FBQztJQUMvQixTQUFTLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBRSxnQkFBZ0IsQ0FBQztJQUM1QyxTQUFTLENBQUMsUUFBUSxDQUFDLGFBQWEsRUFBRSxpQkFBaUIsR0FBRyxTQUFTLENBQUM7SUFDaEUsU0FBUyxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsT0FBTyxLQUFLLENBQUM7SUFDdkMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxnQkFBZ0IsRUFBRSxtQkFBbUIsRUFBRSxDQUFDO0lBQzNELFNBQVMsQ0FBQyxRQUFRLENBQUMscUJBQXFCLEVBQUUsbUJBQW1CLEdBQUcsU0FBUyxDQUFDO0lBRTFFLE9BQU8sQ0FBQyxRQUFRLENBQVM7SUFDekIsT0FBTyxDQUFDLDJCQUEyQixDQUFDLENBQWlCO0lBRXJELHNGQUFzRjtJQUN0RixPQUFPLENBQUMsaUJBQWlCLENBQUMsQ0FBUztJQUNuQyx1RUFBdUU7SUFDdkUsT0FBTyxDQUFDLG9CQUFvQixDQUFDLENBQVM7SUFFdEMsWUFDRSxNQUFNLENBQUMsRUFBRSxnQkFBZ0IsRUFDUixJQUFJLEdBQUU7UUFDckIsTUFBTSxDQUFDLEVBQUUsTUFBTSxDQUFDO1FBQ2hCLGFBQWEsQ0FBQyxFQUFFLGlCQUFpQixDQUFDO1FBQ2xDLGdCQUFnQixDQUFDLEVBQUUsbUJBQW1CLEVBQUUsQ0FBQztRQUN6QyxxQkFBcUIsQ0FBQyxFQUFFLG1CQUFtQixDQUFDO1FBQzVDLHlFQUF5RTtRQUN6RSxjQUFjLENBQUMsRUFBRSxDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsS0FBSyxJQUFJLENBQUM7S0FDckMsRUF3QlA7SUFFRDs7O09BR0c7SUFDSCxPQUFPLENBQUMsc0JBQXNCO0lBVTlCOzs7OztPQUtHO0lBQ0ksV0FBVyxDQUFDLEtBQUssRUFBRSxPQUFPLEdBQUcsSUFBSSxDQUd2QztJQUVZLFdBQVcsa0JBb0V2QjtJQUVZLG9CQUFvQixDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLENBbUJqRTtJQUVEOzs7Ozs7Ozs7Ozs7OztPQWNHO0lBQ1UsY0FBYyxDQUN6QixTQUFTLEVBQUUsS0FBSyxNQUFNLEVBQUUsRUFDeEIsVUFBVSxFQUFFLE1BQU0sRUFBRSxFQUNwQixJQUFJLENBQUMsRUFBRSxxQkFBcUIsR0FDM0IsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLENBa0pqQjtZQVFhLGFBQWE7SUFzQ2Qsa0JBQWtCLENBQzdCLE9BQU8sRUFBRSxNQUFNLEVBQ2YsZUFBZSxFQUFFLE1BQU0sR0FBRyxNQUFNLEVBQ2hDLFVBQVUsR0FBRSxNQUFNLEVBQU8sRUFDekIsb0JBQW9CLENBQUMsRUFBRSxNQUFNLEdBQzVCLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUdqQjtJQUVZLGdCQUFnQixDQUMzQixPQUFPLEVBQUUsTUFBTSxFQUNmLGVBQWUsRUFBRSxNQUFNLEdBQUcsTUFBTSxFQUNoQyxvQkFBb0IsQ0FBQyxFQUFFLE1BQU0sRUFDN0IsVUFBVSxDQUFDLEVBQUUsTUFBTSxFQUFFLEdBQ3BCLE9BQU8sQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQXNDckI7SUFFRCxPQUFPLENBQUMsaUJBQWlCO1lBcUJYLG1CQUFtQjtZQW1DbkIsYUFBYTtJQTZFM0Isc0NBQXNDO0lBQy9CLGdCQUFnQixJQUFJLGlCQUFpQixHQUFHLFNBQVMsQ0FFdkQ7SUFFRCxpRUFBaUU7SUFDMUQsU0FBUyxJQUFJLE9BQU8sQ0FFMUI7SUFFRDs7OztPQUlHO0lBQ1UsS0FBSyxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FXbEM7SUFFRDs7T0FFRztJQUNILE9BQU8sQ0FBQyw4QkFBOEI7WUFnQnhCLGlCQUFpQjtJQTBDL0I7O09BRUc7SUFDSSxJQUFJLElBQUksSUFBSSxDQUtsQjtDQUNGIn0=
87
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NsaWVudC9odHRwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxJQUFJLEVBQUUsS0FBSyxRQUFRLEVBQStCLE1BQU0saUJBQWlCLENBQUM7QUFHbkYsT0FBTyxFQUFFLEtBQUssTUFBTSxFQUFnQixNQUFNLHVCQUF1QixDQUFDO0FBT2xFLE9BQU8sS0FBSyxFQUFFLGlCQUFpQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDakUsT0FBTyxLQUFLLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx1Q0FBdUMsQ0FBQztBQUVqRixPQUFPLEVBQUUsS0FBSyxnQkFBZ0IsRUFBOEIsTUFBTSxhQUFhLENBQUM7QUFDaEYsT0FBTyxLQUFLLEVBQUUsbUJBQW1CLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUVqRixxQkFBYSxjQUFlLFlBQVcsbUJBQW1CO0lBcUJ0RCxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUk7SUFwQnZCLFNBQVMsQ0FBQyxRQUFRLENBQUMsR0FBRyxFQUFFLE1BQU0sQ0FBQztJQUMvQixTQUFTLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBRSxnQkFBZ0IsQ0FBQztJQUM1QyxTQUFTLENBQUMsUUFBUSxDQUFDLGFBQWEsRUFBRSxpQkFBaUIsR0FBRyxTQUFTLENBQUM7SUFDaEUsU0FBUyxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsT0FBTyxLQUFLLENBQUM7SUFDdkMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxnQkFBZ0IsRUFBRSxtQkFBbUIsRUFBRSxDQUFDO0lBQzNELFNBQVMsQ0FBQyxRQUFRLENBQUMscUJBQXFCLEVBQUUsbUJBQW1CLEdBQUcsU0FBUyxDQUFDO0lBRTFFLE9BQU8sQ0FBQyxRQUFRLENBQVM7SUFDekIsT0FBTyxDQUFDLDJCQUEyQixDQUFDLENBQWlCO0lBRXJELHNGQUFzRjtJQUN0RixPQUFPLENBQUMsaUJBQWlCLENBQUMsQ0FBUztJQUNuQyx1RUFBdUU7SUFDdkUsT0FBTyxDQUFDLG9CQUFvQixDQUFDLENBQVM7SUFFdEMsb0dBQW9HO0lBQ3BHLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFjO0lBRTNDLFlBQ0UsTUFBTSxDQUFDLEVBQUUsZ0JBQWdCLEVBQ1IsSUFBSSxHQUFFO1FBQ3JCLE1BQU0sQ0FBQyxFQUFFLE1BQU0sQ0FBQztRQUNoQixhQUFhLENBQUMsRUFBRSxpQkFBaUIsQ0FBQztRQUNsQyxnQkFBZ0IsQ0FBQyxFQUFFLG1CQUFtQixFQUFFLENBQUM7UUFDekMscUJBQXFCLENBQUMsRUFBRSxtQkFBbUIsQ0FBQztRQUM1Qyx5RUFBeUU7UUFDekUsY0FBYyxDQUFDLEVBQUUsQ0FBQyxLQUFLLEVBQUUsSUFBSSxFQUFFLEtBQUssSUFBSSxDQUFDO0tBQ3JDLEVBd0JQO0lBRUQ7OztPQUdHO0lBQ0gsT0FBTyxDQUFDLHNCQUFzQjtJQVU5Qjs7Ozs7T0FLRztJQUNJLFdBQVcsQ0FBQyxLQUFLLEVBQUUsT0FBTyxHQUFHLElBQUksQ0FHdkM7SUFFWSxXQUFXLGtCQStHdkI7SUFFWSxvQkFBb0IsQ0FBQyxLQUFLLEVBQUUsSUFBSSxFQUFFLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQW1CakU7SUFFRDs7Ozs7Ozs7Ozs7T0FXRztJQUNVLGNBQWMsQ0FDekIsU0FBUyxFQUFFLEtBQUssTUFBTSxFQUFFLEVBQ3hCLFVBQVUsRUFBRSxNQUFNLEVBQUUsRUFDcEIsSUFBSSxDQUFDLEVBQUUscUJBQXFCLEdBQzNCLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQXlIakI7SUFFRCx5R0FBeUc7SUFDekcsT0FBTyxDQUFDLGlCQUFpQjtZQW1CWCxpQkFBaUI7WUFtRGpCLGFBQWE7SUFzQ2Qsa0JBQWtCLENBQzdCLE9BQU8sRUFBRSxNQUFNLEVBQ2YsZUFBZSxFQUFFLE1BQU0sR0FBRyxNQUFNLEVBQ2hDLFVBQVUsR0FBRSxNQUFNLEVBQU8sRUFDekIsb0JBQW9CLENBQUMsRUFBRSxNQUFNLEdBQzVCLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUdqQjtJQUVZLGdCQUFnQixDQUMzQixPQUFPLEVBQUUsTUFBTSxFQUNmLGVBQWUsRUFBRSxNQUFNLEdBQUcsTUFBTSxFQUNoQyxvQkFBb0IsQ0FBQyxFQUFFLE1BQU0sRUFDN0IsVUFBVSxDQUFDLEVBQUUsTUFBTSxFQUFFLEdBQ3BCLE9BQU8sQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQXNDckI7SUFFRCxPQUFPLENBQUMsaUJBQWlCO1lBc0JYLG1CQUFtQjtZQW1DbkIsYUFBYTtJQTZFM0Isc0NBQXNDO0lBQy9CLGdCQUFnQixJQUFJLGlCQUFpQixHQUFHLFNBQVMsQ0FFdkQ7SUFFRCxpRUFBaUU7SUFDMUQsU0FBUyxJQUFJLE9BQU8sQ0FFMUI7SUFFRDs7OztPQUlHO0lBQ1UsS0FBSyxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FXbEM7SUFFRDs7T0FFRztJQUNILE9BQU8sQ0FBQyw4QkFBOEI7WUFnQnhCLGlCQUFpQjtJQTBDL0I7O09BRUc7SUFDSSxJQUFJLElBQUksSUFBSSxDQUtsQjtDQUNGIn0=
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/client/http.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/client/http.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,10 @@
1
1
  import { Blob, computeEthVersionedBlobHash } from '@aztec/blob-lib';
2
+ import { makeL1HttpTransport } from '@aztec/ethereum/client';
2
3
  import { shuffle } from '@aztec/foundation/array';
3
4
  import { createLogger } from '@aztec/foundation/log';
4
5
  import { makeBackoff, retry } from '@aztec/foundation/retry';
5
6
  import { bufferToHex, hexToBuffer } from '@aztec/foundation/string';
6
- import { createPublicClient, fallback, http } from 'viem';
7
+ import { createPublicClient } from 'viem';
7
8
  import { createBlobArchiveClient } from '../archive/factory.js';
8
9
  import { DEFAULT_HEALTHCHECK_UPLOAD_INTERVAL_MINUTES } from '../filestore/healthcheck.js';
9
10
  import { getBlobClientConfigFromEnv } from './config.js';
@@ -19,6 +20,7 @@ export class HttpBlobClient {
19
20
  healthcheckUploadIntervalId;
20
21
  /** Cached beacon genesis time (seconds since Unix epoch). Fetched once at startup. */ beaconGenesisTime;
21
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;
22
24
  constructor(config, opts = {}){
23
25
  this.opts = opts;
24
26
  this.disabled = false;
@@ -68,22 +70,52 @@ export class HttpBlobClient {
68
70
  l1ConsensusHostUrls,
69
71
  archiveUrl
70
72
  });
71
- let successfulSourceCount = 0;
73
+ let consensusSuperNodes = 0;
74
+ let consensusNonSuperNodes = 0;
75
+ let archiveSources = 0;
76
+ let blobSinks = 0;
77
+ const detectedSuperNodes = new Set();
72
78
  if (l1ConsensusHostUrls && l1ConsensusHostUrls.length > 0) {
73
79
  for(let l1ConsensusHostIndex = 0; l1ConsensusHostIndex < l1ConsensusHostUrls.length; l1ConsensusHostIndex++){
74
80
  const l1ConsensusHostUrl = l1ConsensusHostUrls[l1ConsensusHostIndex];
75
81
  try {
76
- const { url, ...options } = getBeaconNodeFetchOptions(`${l1ConsensusHostUrl}/eth/v1/beacon/headers`, this.config, l1ConsensusHostIndex);
82
+ const { url, ...options } = getBeaconNodeFetchOptions(`${l1ConsensusHostUrl}/eth/v1/beacon/headers/head`, this.config, l1ConsensusHostIndex);
77
83
  const res = await this.fetch(url, options);
78
- if (res.ok) {
79
- this.log.info(`L1 consensus host is reachable`, {
84
+ if (!res.ok) {
85
+ this.log.error(`Failure reaching L1 consensus host: ${res.statusText} (${res.status})`, {
80
86
  l1ConsensusHostUrl
81
87
  });
82
- successfulSourceCount++;
88
+ continue;
89
+ }
90
+ this.log.info(`L1 consensus host is reachable`, {
91
+ l1ConsensusHostUrl
92
+ });
93
+ // Check if the host serves blob sidecars (supernode/semi-supernode).
94
+ // Post-Fusaka (PeerDAS), non-supernode beacon nodes no longer serve the
95
+ // blob sidecar endpoint. A 200 response (even with an empty data array
96
+ // for a slot with no blobs) means the node supports serving blob sidecars.
97
+ const body = await res.json();
98
+ const headSlot = body?.data?.header?.message?.slot;
99
+ if (headSlot) {
100
+ const { url: blobUrl, ...blobOptions } = getBeaconNodeFetchOptions(`${l1ConsensusHostUrl}/eth/v1/beacon/blobs/${headSlot}`, this.config, l1ConsensusHostIndex);
101
+ const blobRes = await this.fetch(blobUrl, blobOptions);
102
+ if (blobRes.ok) {
103
+ this.log.info(`L1 consensus host serves blob sidecars (supernode)`, {
104
+ l1ConsensusHostUrl
105
+ });
106
+ detectedSuperNodes.add(l1ConsensusHostIndex);
107
+ consensusSuperNodes++;
108
+ } else {
109
+ this.log.info(`L1 consensus host does not serve blob sidecars, skipping for blob fetching`, {
110
+ l1ConsensusHostUrl
111
+ });
112
+ consensusNonSuperNodes++;
113
+ }
83
114
  } else {
84
- this.log.error(`Failure reaching L1 consensus host: ${res.statusText} (${res.status})`, {
115
+ this.log.info(`L1 consensus host is reachable but could not determine head slot`, {
85
116
  l1ConsensusHostUrl
86
117
  });
118
+ consensusNonSuperNodes++;
87
119
  }
88
120
  } catch (err) {
89
121
  this.log.error(`Error reaching L1 consensus host`, err, {
@@ -91,9 +123,8 @@ export class HttpBlobClient {
91
123
  });
92
124
  }
93
125
  }
94
- } else {
95
- this.log.warn('No L1 consensus host urls configured');
96
126
  }
127
+ this.superNodeHostIndexes = detectedSuperNodes;
97
128
  if (this.archiveClient) {
98
129
  try {
99
130
  const latest = await this.archiveClient.getLatestBlock();
@@ -101,14 +132,12 @@ export class HttpBlobClient {
101
132
  latest,
102
133
  archiveUrl
103
134
  });
104
- successfulSourceCount++;
135
+ archiveSources++;
105
136
  } catch (err) {
106
137
  this.log.error(`Error reaching archive client`, err, {
107
138
  archiveUrl
108
139
  });
109
140
  }
110
- } else {
111
- this.log.warn('No archive client configured');
112
141
  }
113
142
  if (this.fileStoreClients.length > 0) {
114
143
  for (const fileStoreClient of this.fileStoreClients){
@@ -118,7 +147,7 @@ export class HttpBlobClient {
118
147
  this.log.info(`FileStore is reachable`, {
119
148
  url: fileStoreClient.getBaseUrl()
120
149
  });
121
- successfulSourceCount++;
150
+ blobSinks++;
122
151
  } else {
123
152
  this.log.warn(`FileStore is not accessible`, {
124
153
  url: fileStoreClient.getBaseUrl()
@@ -131,12 +160,22 @@ export class HttpBlobClient {
131
160
  }
132
161
  }
133
162
  }
163
+ // Emit a single summary after validating all sources
164
+ const successfulSourceCount = consensusSuperNodes + archiveSources + blobSinks;
165
+ let summary = `Blob client running with consensusSuperNodes=${consensusSuperNodes} archiveSources=${archiveSources} blobSinks=${blobSinks}`;
166
+ if (consensusNonSuperNodes > 0) {
167
+ summary += `. ${consensusNonSuperNodes} consensus client(s) ignored because they are not running in supernode or semi-supernode mode`;
168
+ }
134
169
  if (successfulSourceCount === 0) {
135
170
  if (this.config.blobAllowEmptySources) {
136
- this.log.warn('No blob sources are reachable');
171
+ this.log.warn(summary);
137
172
  } else {
138
- throw new Error('No blob sources are reachable');
173
+ throw new Error(summary);
139
174
  }
175
+ } else if (consensusSuperNodes === 0) {
176
+ this.log.warn(summary);
177
+ } else {
178
+ this.log.info(summary);
140
179
  }
141
180
  }
142
181
  async sendBlobsToFilestore(blobs) {
@@ -158,29 +197,25 @@ export class HttpBlobClient {
158
197
  }
159
198
  }
160
199
  /**
161
- * Get the blob sidecar
162
- *
163
- * If requesting from the blob client, we send the blobkHash
164
- * If requesting from the beacon node, we send the slot number
200
+ * Get the blob sidecar.
165
201
  *
166
- * Source ordering depends on sync state:
167
- * - Historical sync: blob client FileStore L1 consensus Archive
168
- * - Near tip sync: blob client → FileStore → L1 consensus → FileStore (with retries) → Archive (eg blobscan)
202
+ * Alternates between two primary sources (consensus and filestore) in a retry loop,
203
+ * then falls back to archive if blobs are still missing. The order of the primary
204
+ * sources is configurable via `blobPreferFilestores`.
169
205
  *
170
206
  * @param blockHash - The block hash
171
207
  * @param blobHashes - The blob hashes to fetch
172
- * @param opts - Options including isHistoricalSync flag
208
+ * @param opts - Options for slot resolution
173
209
  * @returns The blobs
174
210
  */ async getBlobSidecar(blockHash, blobHashes, opts) {
175
211
  if (this.disabled) {
176
212
  this.log.warn('Blob storage is disabled, returning empty blob sidecar');
177
213
  return [];
178
214
  }
179
- const isHistoricalSync = opts?.isHistoricalSync ?? false;
180
215
  // Accumulate blobs across sources, preserving order and handling duplicates
181
216
  // resultBlobs[i] will contain the blob for blobHashes[i], or undefined if not yet found
182
217
  const resultBlobs = new Array(blobHashes.length).fill(undefined);
183
- // Helper to get missing blob hashes that we still need to fetch
218
+ // Helper to get missing blob hashes that we still need to fetch
184
219
  const getMissingBlobHashes = ()=>blobHashes.map((bh, i)=>resultBlobs[i] === undefined ? bh : undefined).filter((bh)=>bh !== undefined);
185
220
  // Return the result, ignoring any undefined ones
186
221
  const getFilledBlobs = ()=>resultBlobs.filter((b)=>b !== undefined);
@@ -202,80 +237,69 @@ export class HttpBlobClient {
202
237
  }
203
238
  return blobs;
204
239
  };
205
- const { l1ConsensusHostUrls } = this.config;
206
240
  const ctx = {
207
241
  blockHash,
208
242
  blobHashes: blobHashes.map(bufferToHex)
209
243
  };
210
- // Try filestore (quick, no retries) - useful for both historical and near-tip sync
211
- if (this.fileStoreClients.length > 0 && getMissingBlobHashes().length > 0) {
212
- await this.tryFileStores(getMissingBlobHashes, fillResults, ctx);
213
- if (getMissingBlobHashes().length === 0) {
214
- return returnWithCallback(getFilledBlobs());
244
+ // Lazily resolve the slot number only resolved when consensus hosts are actually tried.
245
+ let slotNumber;
246
+ let slotResolved = false;
247
+ const getSlotNumber = async ()=>{
248
+ if (!slotResolved) {
249
+ slotNumber = await this.resolveSlotNumber(blockHash, opts);
250
+ slotResolved = true;
215
251
  }
216
- }
217
- const missingAfterSink = getMissingBlobHashes();
218
- if (missingAfterSink.length > 0 && l1ConsensusHostUrls && l1ConsensusHostUrls.length > 0) {
219
- // The beacon api can query by slot number, so we get that first
220
- const consensusCtx = {
221
- l1ConsensusHostUrls,
222
- ...ctx
223
- };
224
- this.log.trace(`Attempting to get slot number for block hash`, consensusCtx);
225
- const slotNumber = await this.getSlotNumber(blockHash, opts?.parentBeaconBlockRoot, opts?.l1BlockTimestamp);
226
- this.log.debug(`Got slot number ${slotNumber} from consensus host for querying blobs`, consensusCtx);
227
- if (slotNumber) {
228
- let l1ConsensusHostUrl;
229
- for(let l1ConsensusHostIndex = 0; l1ConsensusHostIndex < l1ConsensusHostUrls.length; l1ConsensusHostIndex++){
230
- const missingHashes = getMissingBlobHashes();
231
- if (missingHashes.length === 0) {
232
- break;
233
- }
234
- l1ConsensusHostUrl = l1ConsensusHostUrls[l1ConsensusHostIndex];
235
- this.log.trace(`Attempting to get ${missingHashes.length} blobs from consensus host`, {
236
- slotNumber,
237
- l1ConsensusHostUrl,
238
- ...ctx
239
- });
240
- const blobs = await this.getBlobsFromHost(l1ConsensusHostUrl, slotNumber, l1ConsensusHostIndex, getMissingBlobHashes());
241
- const result = await fillResults(blobs);
242
- this.log.debug(`Got ${blobs.length} blobs from consensus host (total: ${result.length}/${blobHashes.length})`, {
243
- slotNumber,
244
- l1ConsensusHostUrl,
245
- ...ctx
246
- });
247
- if (result.length === blobHashes.length) {
248
- return returnWithCallback(result);
249
- }
252
+ return slotNumber;
253
+ };
254
+ // Build the two source-try functions. The order depends on the config.
255
+ const tryConsensus = ()=>this.tryConsensusHosts(getSlotNumber, getMissingBlobHashes, fillResults, ctx);
256
+ const tryFilestores = ()=>this.tryFileStores(getMissingBlobHashes, fillResults, ctx);
257
+ const preferFilestores = this.config.blobPreferFilestores ?? false;
258
+ const [trySourceA, trySourceB] = preferFilestores ? [
259
+ tryFilestores,
260
+ tryConsensus
261
+ ] : [
262
+ tryConsensus,
263
+ tryFilestores
264
+ ];
265
+ // Historical sync: blobs should already exist, use shorter backoff for transient errors.
266
+ // Near-tip sync: blobs may still be uploading, use longer backoff for eventual consistency.
267
+ const isHistoricalSync = opts?.isHistoricalSync ?? false;
268
+ const backoff = isHistoricalSync ? [
269
+ 1,
270
+ 1
271
+ ] : [
272
+ 1,
273
+ 1,
274
+ 1,
275
+ 2,
276
+ 2
277
+ ];
278
+ // Retry loop: alternate between the two primary sources with backoff.
279
+ try {
280
+ await retry(async ()=>{
281
+ if (getMissingBlobHashes().length > 0) {
282
+ await trySourceA();
250
283
  }
251
- }
252
- }
253
- // For near-tip sync, retry filestores with backoff (eventual consistency)
254
- // This handles the case where blobs are still being uploaded by other validators
255
- if (!isHistoricalSync && this.fileStoreClients.length > 0 && getMissingBlobHashes().length > 0) {
256
- try {
257
- await retry(async ()=>{
258
- await this.tryFileStores(getMissingBlobHashes, fillResults, ctx);
259
- if (getMissingBlobHashes().length > 0) {
260
- throw new Error('Still missing blobs from filestores');
261
- }
262
- }, 'filestore blob retrieval', makeBackoff([
263
- 1,
264
- 1,
265
- 2
266
- ]), this.log, true);
267
- return returnWithCallback(getFilledBlobs());
268
- } catch {
269
- // Exhausted retries, continue to archive fallback
270
- }
284
+ if (getMissingBlobHashes().length > 0) {
285
+ await trySourceB();
286
+ }
287
+ if (getMissingBlobHashes().length > 0) {
288
+ throw new Error('Still missing blobs after trying all primary sources');
289
+ }
290
+ }, 'blob retrieval', makeBackoff(backoff), this.log, true);
291
+ return returnWithCallback(getFilledBlobs());
292
+ } catch {
293
+ // Exhausted retries, continue to archive fallback
271
294
  }
272
- const missingAfterConsensus = getMissingBlobHashes();
273
- if (missingAfterConsensus.length > 0 && this.archiveClient) {
295
+ // Archive fallback
296
+ const missingAfterPrimary = getMissingBlobHashes();
297
+ if (missingAfterPrimary.length > 0 && this.archiveClient) {
274
298
  const archiveCtx = {
275
299
  archiveUrl: this.archiveClient.getBaseUrl(),
276
300
  ...ctx
277
301
  };
278
- this.log.trace(`Attempting to get ${missingAfterConsensus.length} blobs from archive`, archiveCtx);
302
+ this.log.trace(`Attempting to get ${missingAfterPrimary.length} blobs from archive`, archiveCtx);
279
303
  const allBlobs = await this.archiveClient.getBlobsFromBlock(blockHash);
280
304
  if (!allBlobs) {
281
305
  this.log.debug('No blobs found from archive client', archiveCtx);
@@ -291,13 +315,63 @@ export class HttpBlobClient {
291
315
  const result = getFilledBlobs();
292
316
  if (result.length < blobHashes.length) {
293
317
  this.log.warn(`Failed to fetch all blobs for ${blockHash} from all blob sources (got ${result.length}/${blobHashes.length})`, {
294
- l1ConsensusHostUrls,
318
+ l1ConsensusHostUrls: this.config.l1ConsensusHostUrls,
295
319
  archiveUrl: this.archiveClient?.getBaseUrl(),
296
320
  fileStoreUrls: this.fileStoreClients.map((c)=>c.getBaseUrl())
297
321
  });
298
322
  }
299
323
  return returnWithCallback(result);
300
324
  }
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
+ }
301
375
  /**
302
376
  * Try all filestores once (shuffled for load distribution).
303
377
  * @param getMissingBlobHashes - Function to get remaining blob hashes to fetch
@@ -384,19 +458,20 @@ export class HttpBlobClient {
384
458
  }
385
459
  baseUrl += `?${params.toString()}`;
386
460
  }
387
- const { url, ...options } = getBeaconNodeFetchOptions(baseUrl, this.config, l1ConsensusHostIndex);
461
+ const { url, logSafeUrl, ...options } = getBeaconNodeFetchOptions(baseUrl, this.config, l1ConsensusHostIndex);
388
462
  this.log.debug(`Fetching blob sidecar for ${blockHashOrSlot}`, {
389
- url,
463
+ url: logSafeUrl,
390
464
  ...options
391
465
  });
392
- return this.fetch(url, options);
466
+ // No retry here — this is called inside the main retry loop in getBlobSidecar
467
+ return fetch(url, options);
393
468
  }
394
469
  async getLatestSlotNumber(hostUrl, l1ConsensusHostIndex) {
395
470
  try {
396
471
  const baseUrl = `${hostUrl}/eth/v1/beacon/headers/head`;
397
- const { url, ...options } = getBeaconNodeFetchOptions(baseUrl, this.config, l1ConsensusHostIndex);
472
+ const { url, logSafeUrl, ...options } = getBeaconNodeFetchOptions(baseUrl, this.config, l1ConsensusHostIndex);
398
473
  this.log.debug(`Fetching latest slot number`, {
399
- url,
474
+ url: logSafeUrl,
400
475
  ...options
401
476
  });
402
477
  const res = await this.fetch(url, options);
@@ -450,9 +525,9 @@ export class HttpBlobClient {
450
525
  return undefined;
451
526
  }
452
527
  const client = createPublicClient({
453
- transport: fallback(l1RpcUrls.map((url)=>http(url, {
454
- batch: false
455
- })))
528
+ transport: makeL1HttpTransport(l1RpcUrls, {
529
+ timeout: this.config.l1HttpTimeoutMS
530
+ })
456
531
  });
457
532
  try {
458
533
  const res = await client.request({
@@ -605,11 +680,15 @@ function getBeaconNodeFetchOptions(url, config, l1ConsensusHostIndex) {
605
680
  const l1ConsensusHostApiKey = l1ConsensusHostIndex !== undefined && l1ConsensusHostApiKeys && l1ConsensusHostApiKeys[l1ConsensusHostIndex];
606
681
  const l1ConsensusHostApiKeyHeader = l1ConsensusHostIndex !== undefined && l1ConsensusHostApiKeyHeaders && l1ConsensusHostApiKeyHeaders[l1ConsensusHostIndex];
607
682
  let formattedUrl = url;
683
+ let logSafeUrl = url;
608
684
  if (l1ConsensusHostApiKey && l1ConsensusHostApiKey.getValue() !== '' && !l1ConsensusHostApiKeyHeader) {
609
- formattedUrl += `${formattedUrl.includes('?') ? '&' : '?'}key=${l1ConsensusHostApiKey.getValue()}`;
685
+ const separator = formattedUrl.includes('?') ? '&' : '?';
686
+ formattedUrl += `${separator}key=${l1ConsensusHostApiKey.getValue()}`;
687
+ logSafeUrl += `${separator}key=[REDACTED]`;
610
688
  }
611
689
  return {
612
690
  url: formattedUrl,
691
+ logSafeUrl,
613
692
  ...l1ConsensusHostApiKey && l1ConsensusHostApiKeyHeader && {
614
693
  headers: {
615
694
  [l1ConsensusHostApiKeyHeader]: l1ConsensusHostApiKey.getValue()
@@ -5,9 +5,7 @@ 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
- * 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)
8
+ * Historical sync uses a shorter retry backoff since blobs should already exist.
11
9
  */
12
10
  isHistoricalSync?: boolean;
13
11
  /**
@@ -36,4 +34,4 @@ export interface BlobClientInterface {
36
34
  /** Returns true if this client can upload blobs to filestore. */
37
35
  canUpload(): boolean;
38
36
  }
39
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZXJmYWNlLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY2xpZW50L2ludGVyZmFjZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxJQUFJLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUU1Qzs7R0FFRztBQUNILE1BQU0sV0FBVyxxQkFBcUI7SUFDcEM7Ozs7O09BS0c7SUFDSCxnQkFBZ0IsQ0FBQyxFQUFFLE9BQU8sQ0FBQztJQUMzQjs7O09BR0c7SUFDSCxxQkFBcUIsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUMvQjs7OztPQUlHO0lBQ0gsZ0JBQWdCLENBQUMsRUFBRSxNQUFNLENBQUM7Q0FDM0I7QUFFRCxNQUFNLFdBQVcsbUJBQW1CO0lBQ2xDLDBFQUEwRTtJQUMxRSxvQkFBb0IsQ0FBQyxLQUFLLEVBQUUsSUFBSSxFQUFFLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3RELHFFQUFxRTtJQUNyRSxjQUFjLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxVQUFVLENBQUMsRUFBRSxNQUFNLEVBQUUsRUFBRSxJQUFJLENBQUMsRUFBRSxxQkFBcUIsR0FBRyxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUN0Ryw2RUFBNkU7SUFDN0UsS0FBSyxDQUFDLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3hCLG9GQUFvRjtJQUNwRixXQUFXLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzdCLDBEQUEwRDtJQUMxRCxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUM7SUFDZCxpRUFBaUU7SUFDakUsU0FBUyxJQUFJLE9BQU8sQ0FBQztDQUN0QiJ9
37
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZXJmYWNlLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY2xpZW50L2ludGVyZmFjZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxJQUFJLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUU1Qzs7R0FFRztBQUNILE1BQU0sV0FBVyxxQkFBcUI7SUFDcEM7OztPQUdHO0lBQ0gsZ0JBQWdCLENBQUMsRUFBRSxPQUFPLENBQUM7SUFDM0I7OztPQUdHO0lBQ0gscUJBQXFCLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDL0I7Ozs7T0FJRztJQUNILGdCQUFnQixDQUFDLEVBQUUsTUFBTSxDQUFDO0NBQzNCO0FBRUQsTUFBTSxXQUFXLG1CQUFtQjtJQUNsQywwRUFBMEU7SUFDMUUsb0JBQW9CLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUN0RCxxRUFBcUU7SUFDckUsY0FBYyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsVUFBVSxDQUFDLEVBQUUsTUFBTSxFQUFFLEVBQUUsSUFBSSxDQUFDLEVBQUUscUJBQXFCLEdBQUcsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7SUFDdEcsNkVBQTZFO0lBQzdFLEtBQUssQ0FBQyxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN4QixvRkFBb0Y7SUFDcEYsV0FBVyxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUM3QiwwREFBMEQ7SUFDMUQsSUFBSSxDQUFDLElBQUksSUFBSSxDQUFDO0lBQ2QsaUVBQWlFO0lBQ2pFLFNBQVMsSUFBSSxPQUFPLENBQUM7Q0FDdEIifQ==
@@ -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;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;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
+ {"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;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;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"}