Skip to content

Commit f2fc318

Browse files
AztecBotspalladino
andauthored
feat: add ETHEREUM_HTTP_TIMEOUT_MS env var for viem HTTP transport (backport #20919) (#21434)
## Summary Backport of #20919 to v4-next. Adds `ETHEREUM_HTTP_TIMEOUT_MS` env var to configure the timeout for viem HTTP transports used in L1 RPC calls. Introduces `makeL1HttpTransport` helper to centralize transport creation with consistent timeout support. ## Conflict Resolution Cherry-pick had a conflict in `blob-client/src/client/http.ts` because `next` had refactored `getSlotNumber` to accept `parentBeaconBlockRoot` as a parameter. Resolved by keeping the v4-next code structure and applying only the transport change (`makeL1HttpTransport` with timeout support). ## Commits 1. Cherry-pick with conflict markers (for reviewability) 2. Conflict resolution ClaudeBox log: https://claudebox.work/s/02b67d20aae96377?run=2 --------- Co-authored-by: Santiago Palladino <santiago@aztec-labs.com>
1 parent 342643f commit f2fc318

11 files changed

Lines changed: 54 additions & 18 deletions

File tree

yarn-project/archiver/src/factory.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { EpochCache } from '@aztec/epoch-cache';
22
import { createEthereumChain } from '@aztec/ethereum/chain';
3+
import { makeL1HttpTransport } from '@aztec/ethereum/client';
34
import { InboxContract, RollupContract } from '@aztec/ethereum/contracts';
45
import type { ViemPublicDebugClient } from '@aztec/ethereum/types';
56
import { BlockNumber } from '@aztec/foundation/branded-types';
@@ -18,7 +19,7 @@ import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
1819
import { getTelemetryClient } from '@aztec/telemetry-client';
1920

2021
import { EventEmitter } from 'events';
21-
import { createPublicClient, fallback, http } from 'viem';
22+
import { createPublicClient } from 'viem';
2223

2324
import { Archiver, type ArchiverDeps } from './archiver.js';
2425
import { type ArchiverConfig, mapArchiverConfig } from './config.js';
@@ -59,17 +60,18 @@ export async function createArchiver(
5960

6061
// Create Ethereum clients
6162
const chain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
63+
const httpTimeout = config.l1HttpTimeoutMS;
6264
const publicClient = createPublicClient({
6365
chain: chain.chainInfo,
64-
transport: fallback(config.l1RpcUrls.map(url => http(url, { batch: false }))),
66+
transport: makeL1HttpTransport(config.l1RpcUrls, { timeout: httpTimeout }),
6567
pollingInterval: config.viemPollingIntervalMS,
6668
});
6769

6870
// Create debug client using debug RPC URLs if available, otherwise fall back to regular RPC URLs
6971
const debugRpcUrls = config.l1DebugRpcUrls.length > 0 ? config.l1DebugRpcUrls : config.l1RpcUrls;
7072
const debugClient = createPublicClient({
7173
chain: chain.chainInfo,
72-
transport: fallback(debugRpcUrls.map(url => http(url, { batch: false }))),
74+
transport: makeL1HttpTransport(debugRpcUrls, { timeout: httpTimeout }),
7375
pollingInterval: config.viemPollingIntervalMS,
7476
}) as ViemPublicDebugClient;
7577

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Blob } from '@aztec/blob-lib';
55
import { ARCHIVE_HEIGHT, type L1_TO_L2_MSG_TREE_HEIGHT, type NOTE_HASH_TREE_HEIGHT } from '@aztec/constants';
66
import { EpochCache, type EpochCacheInterface } from '@aztec/epoch-cache';
77
import { createEthereumChain } from '@aztec/ethereum/chain';
8-
import { getPublicClient } from '@aztec/ethereum/client';
8+
import { getPublicClient, makeL1HttpTransport } from '@aztec/ethereum/client';
99
import { RegistryContract, RollupContract } from '@aztec/ethereum/contracts';
1010
import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
1111
import { BlockNumber, CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
@@ -113,7 +113,7 @@ import {
113113
} from '@aztec/validator-client';
114114
import { createWorldStateSynchronizer } from '@aztec/world-state';
115115

116-
import { createPublicClient, fallback, http } from 'viem';
116+
import { createPublicClient } from 'viem';
117117

118118
import { createSentinel } from '../sentinel/factory.js';
119119
import { Sentinel } from '../sentinel/sentinel.js';
@@ -257,7 +257,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
257257

258258
const publicClient = createPublicClient({
259259
chain: ethereumChain.chainInfo,
260-
transport: fallback(config.l1RpcUrls.map((url: string) => http(url, { batch: false }))),
260+
transport: makeL1HttpTransport(config.l1RpcUrls, { timeout: config.l1HttpTimeoutMS }),
261261
pollingInterval: config.viemPollingIntervalMS,
262262
});
263263

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
SecretValue,
44
booleanConfigHelper,
55
getConfigFromMappings,
6+
optionalNumberConfigHelper,
67
} from '@aztec/foundation/config';
78

89
import { type BlobArchiveApiConfig, blobArchiveApiConfigMappings } from '../archive/config.js';
@@ -55,6 +56,9 @@ export interface BlobClientConfig extends BlobArchiveApiConfig {
5556
* Interval in minutes for uploading healthcheck file to file store (default: 60 = 1 hour)
5657
*/
5758
blobHealthcheckUploadIntervalMinutes?: number;
59+
60+
/** Timeout for HTTP requests to the L1 RPC node in ms. */
61+
l1HttpTimeoutMS?: number;
5862
}
5963

6064
export const blobClientConfigMapping: ConfigMappingsType<BlobClientConfig> = {
@@ -108,6 +112,11 @@ export const blobClientConfigMapping: ConfigMappingsType<BlobClientConfig> = {
108112
description: 'Interval in minutes for uploading healthcheck file to file store (default: 60 = 1 hour)',
109113
parseEnv: (val: string | undefined) => (val ? +val : undefined),
110114
},
115+
l1HttpTimeoutMS: {
116+
env: 'ETHEREUM_HTTP_TIMEOUT_MS',
117+
description: 'Timeout for HTTP requests to the L1 RPC node in ms.',
118+
...optionalNumberConfigHelper(),
119+
},
111120
...blobArchiveApiConfigMappings,
112121
};
113122

yarn-project/blob-client/src/client/http.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { Blob, type BlobJson, computeEthVersionedBlobHash } from '@aztec/blob-lib';
2+
import { makeL1HttpTransport } from '@aztec/ethereum/client';
23
import { shuffle } from '@aztec/foundation/array';
34
import { type Logger, createLogger } from '@aztec/foundation/log';
45
import { makeBackoff, retry } from '@aztec/foundation/retry';
56
import { bufferToHex, hexToBuffer } from '@aztec/foundation/string';
67

7-
import { type RpcBlock, createPublicClient, fallback, http } from 'viem';
8+
import { type RpcBlock, createPublicClient } from 'viem';
89

910
import { createBlobArchiveClient } from '../archive/factory.js';
1011
import type { BlobArchiveClient } from '../archive/interface.js';
@@ -497,7 +498,7 @@ export class HttpBlobClient implements BlobClientInterface {
497498
// Ping execution node to get the parentBeaconBlockRoot for this block
498499
let parentBeaconBlockRoot: string | undefined;
499500
const client = createPublicClient({
500-
transport: fallback(l1RpcUrls.map(url => http(url, { batch: false }))),
501+
transport: makeL1HttpTransport(l1RpcUrls, { timeout: this.config.l1HttpTimeoutMS }),
501502
});
502503
try {
503504
const res: RpcBlock = await client.request({

yarn-project/epoch-cache/src/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { type L1ReaderConfig, getL1ReaderConfigFromEnv } from '@aztec/ethereum/l
33

44
export type EpochCacheConfig = Pick<
55
L1ReaderConfig & L1ContractsConfig,
6-
'l1RpcUrls' | 'l1ChainId' | 'viemPollingIntervalMS' | 'ethereumSlotDuration'
6+
'l1RpcUrls' | 'l1ChainId' | 'viemPollingIntervalMS' | 'l1HttpTimeoutMS' | 'ethereumSlotDuration'
77
>;
88

99
export function getEpochCacheConfigEnvVars(): EpochCacheConfig {

yarn-project/epoch-cache/src/epoch_cache.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { createEthereumChain } from '@aztec/ethereum/chain';
2+
import { makeL1HttpTransport } from '@aztec/ethereum/client';
23
import { NoCommitteeError, RollupContract } from '@aztec/ethereum/contracts';
34
import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
45
import { EthAddress } from '@aztec/foundation/eth-address';
@@ -14,7 +15,7 @@ import {
1415
getTimestampRangeForEpoch,
1516
} from '@aztec/stdlib/epoch-helpers';
1617

17-
import { createPublicClient, encodeAbiParameters, fallback, http, keccak256 } from 'viem';
18+
import { createPublicClient, encodeAbiParameters, keccak256 } from 'viem';
1819

1920
import { type EpochCacheConfig, getEpochCacheConfigEnvVars } from './config.js';
2021

@@ -93,7 +94,7 @@ export class EpochCache implements EpochCacheInterface {
9394
const chain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
9495
const publicClient = createPublicClient({
9596
chain: chain.chainInfo,
96-
transport: fallback(config.l1RpcUrls.map(url => http(url, { batch: false }))),
97+
transport: makeL1HttpTransport(config.l1RpcUrls, { timeout: config.l1HttpTimeoutMS }),
9798
pollingInterval: config.viemPollingIntervalMS,
9899
});
99100
rollup = new RollupContract(publicClient, rollupOrAddress.toString());

yarn-project/ethereum/src/client.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,25 @@ type Config = {
2525
l1ChainId: number;
2626
/** The polling interval viem uses in ms */
2727
viemPollingIntervalMS?: number;
28+
/** Timeout for HTTP requests to the L1 RPC node in ms. */
29+
l1HttpTimeoutMS?: number;
2830
};
2931

3032
export type { Config as EthereumClientConfig };
3133

34+
/** Creates a viem fallback HTTP transport for the given L1 RPC URLs. */
35+
export function makeL1HttpTransport(rpcUrls: string[], opts?: { timeout?: number }) {
36+
return fallback(rpcUrls.map(url => http(url, { batch: false, timeout: opts?.timeout })));
37+
}
38+
3239
// TODO: Use these methods to abstract the creation of viem clients.
3340

3441
/** Returns a viem public client given the L1 config. */
3542
export function getPublicClient(config: Config): ViemPublicClient {
3643
const chain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
3744
return createPublicClient({
3845
chain: chain.chainInfo,
39-
transport: fallback(config.l1RpcUrls.map(url => http(url, { batch: false }))),
46+
transport: makeL1HttpTransport(config.l1RpcUrls, { timeout: config.l1HttpTimeoutMS }),
4047
pollingInterval: config.viemPollingIntervalMS,
4148
});
4249
}
@@ -77,6 +84,7 @@ export function createExtendedL1Client(
7784
chain: Chain = foundry,
7885
pollingIntervalMS?: number,
7986
addressIndex?: number,
87+
opts?: { httpTimeoutMS?: number },
8088
): ExtendedViemWalletClient {
8189
const hdAccount =
8290
typeof mnemonicOrPrivateKeyOrHdAccount === 'string'
@@ -88,7 +96,7 @@ export function createExtendedL1Client(
8896
const extendedClient = createWalletClient({
8997
account: hdAccount,
9098
chain,
91-
transport: fallback(rpcUrls.map(url => http(url, { batch: false }))),
99+
transport: makeL1HttpTransport(rpcUrls, { timeout: opts?.httpTimeoutMS }),
92100
pollingInterval: pollingIntervalMS,
93101
}).extend(publicActions);
94102

yarn-project/ethereum/src/l1_reader.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { type ConfigMappingsType, getConfigFromMappings, numberConfigHelper } from '@aztec/foundation/config';
1+
import {
2+
type ConfigMappingsType,
3+
getConfigFromMappings,
4+
numberConfigHelper,
5+
optionalNumberConfigHelper,
6+
} from '@aztec/foundation/config';
27

38
import { type L1ContractAddresses, l1ContractAddressesMapping } from './l1_contract_addresses.js';
49

@@ -14,6 +19,8 @@ export interface L1ReaderConfig {
1419
l1Contracts: L1ContractAddresses;
1520
/** The polling interval viem uses in ms */
1621
viemPollingIntervalMS: number;
22+
/** Timeout for HTTP requests to the L1 RPC node in ms. */
23+
l1HttpTimeoutMS?: number;
1724
}
1825

1926
export const l1ReaderConfigMappings: ConfigMappingsType<L1ReaderConfig> = {
@@ -43,6 +50,11 @@ export const l1ReaderConfigMappings: ConfigMappingsType<L1ReaderConfig> = {
4350
description: 'The polling interval viem uses in ms',
4451
...numberConfigHelper(1_000),
4552
},
53+
l1HttpTimeoutMS: {
54+
env: 'ETHEREUM_HTTP_TIMEOUT_MS',
55+
description: 'Timeout for HTTP requests to the L1 RPC node in ms.',
56+
...optionalNumberConfigHelper(),
57+
},
4658
};
4759

4860
export function getL1ReaderConfigFromEnv(): L1ReaderConfig {

yarn-project/foundation/src/config/env_var.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ export type EnvVar =
8080
| 'KEY_STORE_DIRECTORY'
8181
| 'L1_CHAIN_ID'
8282
| 'L1_CONSENSUS_HOST_URLS'
83+
| 'ETHEREUM_HTTP_TIMEOUT_MS'
8384
| 'L1_CONSENSUS_HOST_API_KEYS'
8485
| 'L1_CONSENSUS_HOST_API_KEY_HEADERS'
8586
| 'LOG_JSON'

yarn-project/prover-node/src/factory.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { BlobClientInterface } from '@aztec/blob-client/client';
33
import { Blob } from '@aztec/blob-lib';
44
import type { EpochCacheInterface } from '@aztec/epoch-cache';
55
import { createEthereumChain } from '@aztec/ethereum/chain';
6+
import { makeL1HttpTransport } from '@aztec/ethereum/client';
67
import { RollupContract } from '@aztec/ethereum/contracts';
78
import { L1TxUtils } from '@aztec/ethereum/l1-tx-utils';
89
import { PublisherManager } from '@aztec/ethereum/publisher-manager';
@@ -27,7 +28,7 @@ import type {
2728
} from '@aztec/stdlib/interfaces/server';
2829
import { L1Metrics, type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
2930

30-
import { createPublicClient, fallback, http } from 'viem';
31+
import { createPublicClient } from 'viem';
3132

3233
import type { SpecificProverNodeConfig } from './config.js';
3334
import { EpochMonitor } from './monitors/epoch-monitor.js';
@@ -95,7 +96,7 @@ export async function createProverNode(
9596

9697
const publicClient = createPublicClient({
9798
chain: chain.chainInfo,
98-
transport: fallback(config.l1RpcUrls.map((url: string) => http(url, { batch: false }))),
99+
transport: makeL1HttpTransport(config.l1RpcUrls, { timeout: config.l1HttpTimeoutMS }),
99100
pollingInterval: config.viemPollingIntervalMS,
100101
});
101102

0 commit comments

Comments
 (0)