From 51aea55f6a8b09f6334b37b0e45e377890755543 Mon Sep 17 00:00:00 2001 From: Sam Calder-Mason Date: Thu, 12 Feb 2026 14:25:31 +1000 Subject: [PATCH 01/15] feat: add Node Resources tab to slot detail page Add CPU utilization visualization to the slot detail page, powered by observoor eBPF agent data via the new fct_node_cpu_utilization model. Features: - Per-node CL/EL CPU utilization chart (0-12s slot window) - Aggregate view (mean/min/max toggle) and single-node detailed view - Normalized system utilization (sys mean/min/max) and hottest single core - EIP-7870 reference nodes filter toggle - Block arrival time overlay (markLines) - URL-backed state for node selection, metric, and filter --- src/api/@tanstack/react-query.gen.ts | 314 ++- src/api/client/client.gen.ts | 8 +- src/api/index.ts | 90 +- src/api/sdk.gen.ts | 244 +- src/api/types.gen.ts | 2166 ++++++++++++++- src/api/zod.gen.ts | 2419 +++++++++++++++-- src/pages/ethereum/slots/DetailPage.tsx | 11 + .../NodeResources/CpuUtilizationChart.tsx | 317 +++ .../NodeResources/NodeResourcesPanel.tsx | 210 ++ .../components/NodeResources/NodeSelector.tsx | 45 + .../slots/components/NodeResources/index.ts | 1 + .../slots/hooks/useSlotNodeResources/index.ts | 2 + .../useSlotNodeResources.ts | 38 + src/routes/ethereum/slots/$slot.tsx | 5 +- 14 files changed, 5491 insertions(+), 379 deletions(-) create mode 100644 src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx create mode 100644 src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx create mode 100644 src/pages/ethereum/slots/components/NodeResources/NodeSelector.tsx create mode 100644 src/pages/ethereum/slots/components/NodeResources/index.ts create mode 100644 src/pages/ethereum/slots/hooks/useSlotNodeResources/index.ts create mode 100644 src/pages/ethereum/slots/hooks/useSlotNodeResources/useSlotNodeResources.ts diff --git a/src/api/@tanstack/react-query.gen.ts b/src/api/@tanstack/react-query.gen.ts index 7dc5820fb..d588ae456 100644 --- a/src/api/@tanstack/react-query.gen.ts +++ b/src/api/@tanstack/react-query.gen.ts @@ -184,6 +184,8 @@ import { fctMissedSlotRateHourlyServiceList, fctNodeActiveLast24hServiceGet, fctNodeActiveLast24hServiceList, + fctNodeCpuUtilizationServiceGet, + fctNodeCpuUtilizationServiceList, fctOpcodeGasByOpcodeDailyServiceGet, fctOpcodeGasByOpcodeDailyServiceList, fctOpcodeGasByOpcodeHourlyServiceGet, @@ -260,6 +262,10 @@ import { intBlockOpcodeGasServiceList, intBlockProposerCanonicalServiceGet, intBlockProposerCanonicalServiceList, + intContractCreationServiceGet, + intContractCreationServiceList, + intContractSelfdestructServiceGet, + intContractSelfdestructServiceList, intContractStorageExpiry12mServiceGet, intContractStorageExpiry12mServiceList, intContractStorageExpiry18mServiceGet, @@ -300,12 +306,14 @@ import { intCustodyProbeServiceList, intEngineGetBlobsServiceGet, intEngineGetBlobsServiceList, - intEngineNewPayloadFastestServiceGet, - intEngineNewPayloadFastestServiceList, + intEngineNewPayloadFastestExecutionByNodeClassServiceGet, + intEngineNewPayloadFastestExecutionByNodeClassServiceList, intEngineNewPayloadServiceGet, intEngineNewPayloadServiceList, intExecutionBlockByDateServiceGet, intExecutionBlockByDateServiceList, + intStorageSelfdestructDiffsServiceGet, + intStorageSelfdestructDiffsServiceList, intStorageSlotDiffByAddressSlotServiceGet, intStorageSlotDiffByAddressSlotServiceList, intStorageSlotDiffServiceGet, @@ -895,6 +903,12 @@ import type { FctNodeActiveLast24hServiceListData, FctNodeActiveLast24hServiceListError, FctNodeActiveLast24hServiceListResponse, + FctNodeCpuUtilizationServiceGetData, + FctNodeCpuUtilizationServiceGetError, + FctNodeCpuUtilizationServiceGetResponse, + FctNodeCpuUtilizationServiceListData, + FctNodeCpuUtilizationServiceListError, + FctNodeCpuUtilizationServiceListResponse, FctOpcodeGasByOpcodeDailyServiceGetData, FctOpcodeGasByOpcodeDailyServiceGetError, FctOpcodeGasByOpcodeDailyServiceGetResponse, @@ -1123,6 +1137,18 @@ import type { IntBlockProposerCanonicalServiceListData, IntBlockProposerCanonicalServiceListError, IntBlockProposerCanonicalServiceListResponse, + IntContractCreationServiceGetData, + IntContractCreationServiceGetError, + IntContractCreationServiceGetResponse, + IntContractCreationServiceListData, + IntContractCreationServiceListError, + IntContractCreationServiceListResponse, + IntContractSelfdestructServiceGetData, + IntContractSelfdestructServiceGetError, + IntContractSelfdestructServiceGetResponse, + IntContractSelfdestructServiceListData, + IntContractSelfdestructServiceListError, + IntContractSelfdestructServiceListResponse, IntContractStorageExpiry12mServiceGetData, IntContractStorageExpiry12mServiceGetError, IntContractStorageExpiry12mServiceGetResponse, @@ -1243,12 +1269,12 @@ import type { IntEngineGetBlobsServiceListData, IntEngineGetBlobsServiceListError, IntEngineGetBlobsServiceListResponse, - IntEngineNewPayloadFastestServiceGetData, - IntEngineNewPayloadFastestServiceGetError, - IntEngineNewPayloadFastestServiceGetResponse, - IntEngineNewPayloadFastestServiceListData, - IntEngineNewPayloadFastestServiceListError, - IntEngineNewPayloadFastestServiceListResponse, + IntEngineNewPayloadFastestExecutionByNodeClassServiceGetData, + IntEngineNewPayloadFastestExecutionByNodeClassServiceGetError, + IntEngineNewPayloadFastestExecutionByNodeClassServiceGetResponse, + IntEngineNewPayloadFastestExecutionByNodeClassServiceListData, + IntEngineNewPayloadFastestExecutionByNodeClassServiceListError, + IntEngineNewPayloadFastestExecutionByNodeClassServiceListResponse, IntEngineNewPayloadServiceGetData, IntEngineNewPayloadServiceGetError, IntEngineNewPayloadServiceGetResponse, @@ -1261,6 +1287,12 @@ import type { IntExecutionBlockByDateServiceListData, IntExecutionBlockByDateServiceListError, IntExecutionBlockByDateServiceListResponse, + IntStorageSelfdestructDiffsServiceGetData, + IntStorageSelfdestructDiffsServiceGetError, + IntStorageSelfdestructDiffsServiceGetResponse, + IntStorageSelfdestructDiffsServiceListData, + IntStorageSelfdestructDiffsServiceListError, + IntStorageSelfdestructDiffsServiceListResponse, IntStorageSlotDiffByAddressSlotServiceGetData, IntStorageSlotDiffByAddressSlotServiceGetError, IntStorageSlotDiffByAddressSlotServiceGetResponse, @@ -6651,6 +6683,60 @@ export const fctNodeActiveLast24hServiceGetOptions = (options: Options) => + createQueryKey('fctNodeCpuUtilizationServiceList', options); + +/** + * List records + * + * Retrieve paginated results with optional filtering + */ +export const fctNodeCpuUtilizationServiceListOptions = (options?: Options) => + queryOptions< + FctNodeCpuUtilizationServiceListResponse, + FctNodeCpuUtilizationServiceListError, + FctNodeCpuUtilizationServiceListResponse, + ReturnType + >({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await fctNodeCpuUtilizationServiceList({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: fctNodeCpuUtilizationServiceListQueryKey(options), + }); + +export const fctNodeCpuUtilizationServiceGetQueryKey = (options: Options) => + createQueryKey('fctNodeCpuUtilizationServiceGet', options); + +/** + * Get record + * + * Retrieve a single record by wallclock_slot_start_date_time + */ +export const fctNodeCpuUtilizationServiceGetOptions = (options: Options) => + queryOptions< + FctNodeCpuUtilizationServiceGetResponse, + FctNodeCpuUtilizationServiceGetError, + FctNodeCpuUtilizationServiceGetResponse, + ReturnType + >({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await fctNodeCpuUtilizationServiceGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: fctNodeCpuUtilizationServiceGetQueryKey(options), + }); + export const fctOpcodeGasByOpcodeDailyServiceListQueryKey = ( options?: Options ) => createQueryKey('fctOpcodeGasByOpcodeDailyServiceList', options); @@ -8832,6 +8918,114 @@ export const intBlockProposerCanonicalServiceGetOptions = (options: Options) => + createQueryKey('intContractCreationServiceList', options); + +/** + * List records + * + * Retrieve paginated results with optional filtering + */ +export const intContractCreationServiceListOptions = (options?: Options) => + queryOptions< + IntContractCreationServiceListResponse, + IntContractCreationServiceListError, + IntContractCreationServiceListResponse, + ReturnType + >({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await intContractCreationServiceList({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: intContractCreationServiceListQueryKey(options), + }); + +export const intContractCreationServiceGetQueryKey = (options: Options) => + createQueryKey('intContractCreationServiceGet', options); + +/** + * Get record + * + * Retrieve a single record by block_number + */ +export const intContractCreationServiceGetOptions = (options: Options) => + queryOptions< + IntContractCreationServiceGetResponse, + IntContractCreationServiceGetError, + IntContractCreationServiceGetResponse, + ReturnType + >({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await intContractCreationServiceGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: intContractCreationServiceGetQueryKey(options), + }); + +export const intContractSelfdestructServiceListQueryKey = (options?: Options) => + createQueryKey('intContractSelfdestructServiceList', options); + +/** + * List records + * + * Retrieve paginated results with optional filtering + */ +export const intContractSelfdestructServiceListOptions = (options?: Options) => + queryOptions< + IntContractSelfdestructServiceListResponse, + IntContractSelfdestructServiceListError, + IntContractSelfdestructServiceListResponse, + ReturnType + >({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await intContractSelfdestructServiceList({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: intContractSelfdestructServiceListQueryKey(options), + }); + +export const intContractSelfdestructServiceGetQueryKey = (options: Options) => + createQueryKey('intContractSelfdestructServiceGet', options); + +/** + * Get record + * + * Retrieve a single record by block_number + */ +export const intContractSelfdestructServiceGetOptions = (options: Options) => + queryOptions< + IntContractSelfdestructServiceGetResponse, + IntContractSelfdestructServiceGetError, + IntContractSelfdestructServiceGetResponse, + ReturnType + >({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await intContractSelfdestructServiceGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: intContractSelfdestructServiceGetQueryKey(options), + }); + export const intContractStorageExpiry1mServiceListQueryKey = ( options?: Options ) => createQueryKey('intContractStorageExpiry1mServiceList', options); @@ -10068,26 +10262,26 @@ export const intEngineNewPayloadServiceGetOptions = (options: Options -) => createQueryKey('intEngineNewPayloadFastestServiceList', options); +export const intEngineNewPayloadFastestExecutionByNodeClassServiceListQueryKey = ( + options?: Options +) => createQueryKey('intEngineNewPayloadFastestExecutionByNodeClassServiceList', options); /** * List records * * Retrieve paginated results with optional filtering */ -export const intEngineNewPayloadFastestServiceListOptions = ( - options?: Options +export const intEngineNewPayloadFastestExecutionByNodeClassServiceListOptions = ( + options?: Options ) => queryOptions< - IntEngineNewPayloadFastestServiceListResponse, - IntEngineNewPayloadFastestServiceListError, - IntEngineNewPayloadFastestServiceListResponse, - ReturnType + IntEngineNewPayloadFastestExecutionByNodeClassServiceListResponse, + IntEngineNewPayloadFastestExecutionByNodeClassServiceListError, + IntEngineNewPayloadFastestExecutionByNodeClassServiceListResponse, + ReturnType >({ queryFn: async ({ queryKey, signal }) => { - const { data } = await intEngineNewPayloadFastestServiceList({ + const { data } = await intEngineNewPayloadFastestExecutionByNodeClassServiceList({ ...options, ...queryKey[0], signal, @@ -10095,29 +10289,29 @@ export const intEngineNewPayloadFastestServiceListOptions = ( }); return data; }, - queryKey: intEngineNewPayloadFastestServiceListQueryKey(options), + queryKey: intEngineNewPayloadFastestExecutionByNodeClassServiceListQueryKey(options), }); -export const intEngineNewPayloadFastestServiceGetQueryKey = ( - options: Options -) => createQueryKey('intEngineNewPayloadFastestServiceGet', options); +export const intEngineNewPayloadFastestExecutionByNodeClassServiceGetQueryKey = ( + options: Options +) => createQueryKey('intEngineNewPayloadFastestExecutionByNodeClassServiceGet', options); /** * Get record * * Retrieve a single record by slot_start_date_time */ -export const intEngineNewPayloadFastestServiceGetOptions = ( - options: Options +export const intEngineNewPayloadFastestExecutionByNodeClassServiceGetOptions = ( + options: Options ) => queryOptions< - IntEngineNewPayloadFastestServiceGetResponse, - IntEngineNewPayloadFastestServiceGetError, - IntEngineNewPayloadFastestServiceGetResponse, - ReturnType + IntEngineNewPayloadFastestExecutionByNodeClassServiceGetResponse, + IntEngineNewPayloadFastestExecutionByNodeClassServiceGetError, + IntEngineNewPayloadFastestExecutionByNodeClassServiceGetResponse, + ReturnType >({ queryFn: async ({ queryKey, signal }) => { - const { data } = await intEngineNewPayloadFastestServiceGet({ + const { data } = await intEngineNewPayloadFastestExecutionByNodeClassServiceGet({ ...options, ...queryKey[0], signal, @@ -10125,7 +10319,7 @@ export const intEngineNewPayloadFastestServiceGetOptions = ( }); return data; }, - queryKey: intEngineNewPayloadFastestServiceGetQueryKey(options), + queryKey: intEngineNewPayloadFastestExecutionByNodeClassServiceGetQueryKey(options), }); export const intExecutionBlockByDateServiceListQueryKey = (options?: Options) => @@ -10182,6 +10376,66 @@ export const intExecutionBlockByDateServiceGetOptions = (options: Options +) => createQueryKey('intStorageSelfdestructDiffsServiceList', options); + +/** + * List records + * + * Retrieve paginated results with optional filtering + */ +export const intStorageSelfdestructDiffsServiceListOptions = ( + options?: Options +) => + queryOptions< + IntStorageSelfdestructDiffsServiceListResponse, + IntStorageSelfdestructDiffsServiceListError, + IntStorageSelfdestructDiffsServiceListResponse, + ReturnType + >({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await intStorageSelfdestructDiffsServiceList({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: intStorageSelfdestructDiffsServiceListQueryKey(options), + }); + +export const intStorageSelfdestructDiffsServiceGetQueryKey = ( + options: Options +) => createQueryKey('intStorageSelfdestructDiffsServiceGet', options); + +/** + * Get record + * + * Retrieve a single record by block_number + */ +export const intStorageSelfdestructDiffsServiceGetOptions = ( + options: Options +) => + queryOptions< + IntStorageSelfdestructDiffsServiceGetResponse, + IntStorageSelfdestructDiffsServiceGetError, + IntStorageSelfdestructDiffsServiceGetResponse, + ReturnType + >({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await intStorageSelfdestructDiffsServiceGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: intStorageSelfdestructDiffsServiceGetQueryKey(options), + }); + export const intStorageSlotDiffServiceListQueryKey = (options?: Options) => createQueryKey('intStorageSlotDiffServiceList', options); diff --git a/src/api/client/client.gen.ts b/src/api/client/client.gen.ts index c445e3e5a..1eaee37dd 100644 --- a/src/api/client/client.gen.ts +++ b/src/api/client/client.gen.ts @@ -162,10 +162,16 @@ export const createClient = (config: Config = {}): Client => { case 'arrayBuffer': case 'blob': case 'formData': - case 'json': case 'text': data = await response[parseAs](); break; + case 'json': { + // Some servers return 200 with no Content-Length and empty body. + // response.json() would throw; read as text and parse if non-empty. + const text = await response.text(); + data = text ? JSON.parse(text) : {}; + break; + } case 'stream': return opts.responseStyle === 'data' ? response.body diff --git a/src/api/index.ts b/src/api/index.ts index 810997ab1..37ec5f40a 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -181,6 +181,8 @@ export { fctMissedSlotRateHourlyServiceList, fctNodeActiveLast24hServiceGet, fctNodeActiveLast24hServiceList, + fctNodeCpuUtilizationServiceGet, + fctNodeCpuUtilizationServiceList, fctOpcodeGasByOpcodeDailyServiceGet, fctOpcodeGasByOpcodeDailyServiceList, fctOpcodeGasByOpcodeHourlyServiceGet, @@ -257,6 +259,10 @@ export { intBlockOpcodeGasServiceList, intBlockProposerCanonicalServiceGet, intBlockProposerCanonicalServiceList, + intContractCreationServiceGet, + intContractCreationServiceList, + intContractSelfdestructServiceGet, + intContractSelfdestructServiceList, intContractStorageExpiry12mServiceGet, intContractStorageExpiry12mServiceList, intContractStorageExpiry18mServiceGet, @@ -297,12 +303,14 @@ export { intCustodyProbeServiceList, intEngineGetBlobsServiceGet, intEngineGetBlobsServiceList, - intEngineNewPayloadFastestServiceGet, - intEngineNewPayloadFastestServiceList, + intEngineNewPayloadFastestExecutionByNodeClassServiceGet, + intEngineNewPayloadFastestExecutionByNodeClassServiceList, intEngineNewPayloadServiceGet, intEngineNewPayloadServiceList, intExecutionBlockByDateServiceGet, intExecutionBlockByDateServiceList, + intStorageSelfdestructDiffsServiceGet, + intStorageSelfdestructDiffsServiceList, intStorageSlotDiffByAddressSlotServiceGet, intStorageSlotDiffByAddressSlotServiceList, intStorageSlotDiffServiceGet, @@ -1343,6 +1351,17 @@ export type { FctNodeActiveLast24hServiceListErrors, FctNodeActiveLast24hServiceListResponse, FctNodeActiveLast24hServiceListResponses, + FctNodeCpuUtilization, + FctNodeCpuUtilizationServiceGetData, + FctNodeCpuUtilizationServiceGetError, + FctNodeCpuUtilizationServiceGetErrors, + FctNodeCpuUtilizationServiceGetResponse, + FctNodeCpuUtilizationServiceGetResponses, + FctNodeCpuUtilizationServiceListData, + FctNodeCpuUtilizationServiceListError, + FctNodeCpuUtilizationServiceListErrors, + FctNodeCpuUtilizationServiceListResponse, + FctNodeCpuUtilizationServiceListResponses, FctOpcodeGasByOpcodeDaily, FctOpcodeGasByOpcodeDailyServiceGetData, FctOpcodeGasByOpcodeDailyServiceGetError, @@ -1708,6 +1727,7 @@ export type { GetFctMissedSlotRateDailyResponse, GetFctMissedSlotRateHourlyResponse, GetFctNodeActiveLast24hResponse, + GetFctNodeCpuUtilizationResponse, GetFctOpcodeGasByOpcodeDailyResponse, GetFctOpcodeGasByOpcodeHourlyResponse, GetFctOpcodeOpsDailyResponse, @@ -1746,6 +1766,8 @@ export type { GetIntBlockMevCanonicalResponse, GetIntBlockOpcodeGasResponse, GetIntBlockProposerCanonicalResponse, + GetIntContractCreationResponse, + GetIntContractSelfdestructResponse, GetIntContractStorageExpiry12mResponse, GetIntContractStorageExpiry18mResponse, GetIntContractStorageExpiry1mResponse, @@ -1766,9 +1788,10 @@ export type { GetIntCustodyProbeOrderBySlotResponse, GetIntCustodyProbeResponse, GetIntEngineGetBlobsResponse, - GetIntEngineNewPayloadFastestResponse, + GetIntEngineNewPayloadFastestExecutionByNodeClassResponse, GetIntEngineNewPayloadResponse, GetIntExecutionBlockByDateResponse, + GetIntStorageSelfdestructDiffsResponse, GetIntStorageSlotDiffByAddressSlotResponse, GetIntStorageSlotDiffResponse, GetIntStorageSlotExpiry12mResponse, @@ -1936,6 +1959,28 @@ export type { IntBlockProposerCanonicalServiceListErrors, IntBlockProposerCanonicalServiceListResponse, IntBlockProposerCanonicalServiceListResponses, + IntContractCreation, + IntContractCreationServiceGetData, + IntContractCreationServiceGetError, + IntContractCreationServiceGetErrors, + IntContractCreationServiceGetResponse, + IntContractCreationServiceGetResponses, + IntContractCreationServiceListData, + IntContractCreationServiceListError, + IntContractCreationServiceListErrors, + IntContractCreationServiceListResponse, + IntContractCreationServiceListResponses, + IntContractSelfdestruct, + IntContractSelfdestructServiceGetData, + IntContractSelfdestructServiceGetError, + IntContractSelfdestructServiceGetErrors, + IntContractSelfdestructServiceGetResponse, + IntContractSelfdestructServiceGetResponses, + IntContractSelfdestructServiceListData, + IntContractSelfdestructServiceListError, + IntContractSelfdestructServiceListErrors, + IntContractSelfdestructServiceListResponse, + IntContractSelfdestructServiceListResponses, IntContractStorageExpiry12m, IntContractStorageExpiry12mServiceGetData, IntContractStorageExpiry12mServiceGetError, @@ -2157,17 +2202,17 @@ export type { IntEngineGetBlobsServiceListResponse, IntEngineGetBlobsServiceListResponses, IntEngineNewPayload, - IntEngineNewPayloadFastest, - IntEngineNewPayloadFastestServiceGetData, - IntEngineNewPayloadFastestServiceGetError, - IntEngineNewPayloadFastestServiceGetErrors, - IntEngineNewPayloadFastestServiceGetResponse, - IntEngineNewPayloadFastestServiceGetResponses, - IntEngineNewPayloadFastestServiceListData, - IntEngineNewPayloadFastestServiceListError, - IntEngineNewPayloadFastestServiceListErrors, - IntEngineNewPayloadFastestServiceListResponse, - IntEngineNewPayloadFastestServiceListResponses, + IntEngineNewPayloadFastestExecutionByNodeClass, + IntEngineNewPayloadFastestExecutionByNodeClassServiceGetData, + IntEngineNewPayloadFastestExecutionByNodeClassServiceGetError, + IntEngineNewPayloadFastestExecutionByNodeClassServiceGetErrors, + IntEngineNewPayloadFastestExecutionByNodeClassServiceGetResponse, + IntEngineNewPayloadFastestExecutionByNodeClassServiceGetResponses, + IntEngineNewPayloadFastestExecutionByNodeClassServiceListData, + IntEngineNewPayloadFastestExecutionByNodeClassServiceListError, + IntEngineNewPayloadFastestExecutionByNodeClassServiceListErrors, + IntEngineNewPayloadFastestExecutionByNodeClassServiceListResponse, + IntEngineNewPayloadFastestExecutionByNodeClassServiceListResponses, IntEngineNewPayloadServiceGetData, IntEngineNewPayloadServiceGetError, IntEngineNewPayloadServiceGetErrors, @@ -2189,6 +2234,17 @@ export type { IntExecutionBlockByDateServiceListErrors, IntExecutionBlockByDateServiceListResponse, IntExecutionBlockByDateServiceListResponses, + IntStorageSelfdestructDiffs, + IntStorageSelfdestructDiffsServiceGetData, + IntStorageSelfdestructDiffsServiceGetError, + IntStorageSelfdestructDiffsServiceGetErrors, + IntStorageSelfdestructDiffsServiceGetResponse, + IntStorageSelfdestructDiffsServiceGetResponses, + IntStorageSelfdestructDiffsServiceListData, + IntStorageSelfdestructDiffsServiceListError, + IntStorageSelfdestructDiffsServiceListErrors, + IntStorageSelfdestructDiffsServiceListResponse, + IntStorageSelfdestructDiffsServiceListResponses, IntStorageSlotDiff, IntStorageSlotDiffByAddressSlot, IntStorageSlotDiffByAddressSlotServiceGetData, @@ -2532,6 +2588,7 @@ export type { ListFctMissedSlotRateDailyResponse, ListFctMissedSlotRateHourlyResponse, ListFctNodeActiveLast24hResponse, + ListFctNodeCpuUtilizationResponse, ListFctOpcodeGasByOpcodeDailyResponse, ListFctOpcodeGasByOpcodeHourlyResponse, ListFctOpcodeOpsDailyResponse, @@ -2570,6 +2627,8 @@ export type { ListIntBlockMevCanonicalResponse, ListIntBlockOpcodeGasResponse, ListIntBlockProposerCanonicalResponse, + ListIntContractCreationResponse, + ListIntContractSelfdestructResponse, ListIntContractStorageExpiry12mResponse, ListIntContractStorageExpiry18mResponse, ListIntContractStorageExpiry1mResponse, @@ -2590,9 +2649,10 @@ export type { ListIntCustodyProbeOrderBySlotResponse, ListIntCustodyProbeResponse, ListIntEngineGetBlobsResponse, - ListIntEngineNewPayloadFastestResponse, + ListIntEngineNewPayloadFastestExecutionByNodeClassResponse, ListIntEngineNewPayloadResponse, ListIntExecutionBlockByDateResponse, + ListIntStorageSelfdestructDiffsResponse, ListIntStorageSlotDiffByAddressSlotResponse, ListIntStorageSlotDiffResponse, ListIntStorageSlotExpiry12mResponse, diff --git a/src/api/sdk.gen.ts b/src/api/sdk.gen.ts index 42d4e69c8..fda9063a1 100644 --- a/src/api/sdk.gen.ts +++ b/src/api/sdk.gen.ts @@ -543,6 +543,12 @@ import type { FctNodeActiveLast24hServiceListData, FctNodeActiveLast24hServiceListErrors, FctNodeActiveLast24hServiceListResponses, + FctNodeCpuUtilizationServiceGetData, + FctNodeCpuUtilizationServiceGetErrors, + FctNodeCpuUtilizationServiceGetResponses, + FctNodeCpuUtilizationServiceListData, + FctNodeCpuUtilizationServiceListErrors, + FctNodeCpuUtilizationServiceListResponses, FctOpcodeGasByOpcodeDailyServiceGetData, FctOpcodeGasByOpcodeDailyServiceGetErrors, FctOpcodeGasByOpcodeDailyServiceGetResponses, @@ -771,6 +777,18 @@ import type { IntBlockProposerCanonicalServiceListData, IntBlockProposerCanonicalServiceListErrors, IntBlockProposerCanonicalServiceListResponses, + IntContractCreationServiceGetData, + IntContractCreationServiceGetErrors, + IntContractCreationServiceGetResponses, + IntContractCreationServiceListData, + IntContractCreationServiceListErrors, + IntContractCreationServiceListResponses, + IntContractSelfdestructServiceGetData, + IntContractSelfdestructServiceGetErrors, + IntContractSelfdestructServiceGetResponses, + IntContractSelfdestructServiceListData, + IntContractSelfdestructServiceListErrors, + IntContractSelfdestructServiceListResponses, IntContractStorageExpiry12mServiceGetData, IntContractStorageExpiry12mServiceGetErrors, IntContractStorageExpiry12mServiceGetResponses, @@ -891,12 +909,12 @@ import type { IntEngineGetBlobsServiceListData, IntEngineGetBlobsServiceListErrors, IntEngineGetBlobsServiceListResponses, - IntEngineNewPayloadFastestServiceGetData, - IntEngineNewPayloadFastestServiceGetErrors, - IntEngineNewPayloadFastestServiceGetResponses, - IntEngineNewPayloadFastestServiceListData, - IntEngineNewPayloadFastestServiceListErrors, - IntEngineNewPayloadFastestServiceListResponses, + IntEngineNewPayloadFastestExecutionByNodeClassServiceGetData, + IntEngineNewPayloadFastestExecutionByNodeClassServiceGetErrors, + IntEngineNewPayloadFastestExecutionByNodeClassServiceGetResponses, + IntEngineNewPayloadFastestExecutionByNodeClassServiceListData, + IntEngineNewPayloadFastestExecutionByNodeClassServiceListErrors, + IntEngineNewPayloadFastestExecutionByNodeClassServiceListResponses, IntEngineNewPayloadServiceGetData, IntEngineNewPayloadServiceGetErrors, IntEngineNewPayloadServiceGetResponses, @@ -909,6 +927,12 @@ import type { IntExecutionBlockByDateServiceListData, IntExecutionBlockByDateServiceListErrors, IntExecutionBlockByDateServiceListResponses, + IntStorageSelfdestructDiffsServiceGetData, + IntStorageSelfdestructDiffsServiceGetErrors, + IntStorageSelfdestructDiffsServiceGetResponses, + IntStorageSelfdestructDiffsServiceListData, + IntStorageSelfdestructDiffsServiceListErrors, + IntStorageSelfdestructDiffsServiceListResponses, IntStorageSlotDiffByAddressSlotServiceGetData, IntStorageSlotDiffByAddressSlotServiceGetErrors, IntStorageSlotDiffByAddressSlotServiceGetResponses, @@ -1409,6 +1433,10 @@ import { zFctNodeActiveLast24hServiceGetResponse, zFctNodeActiveLast24hServiceListData, zFctNodeActiveLast24hServiceListResponse, + zFctNodeCpuUtilizationServiceGetData, + zFctNodeCpuUtilizationServiceGetResponse, + zFctNodeCpuUtilizationServiceListData, + zFctNodeCpuUtilizationServiceListResponse, zFctOpcodeGasByOpcodeDailyServiceGetData, zFctOpcodeGasByOpcodeDailyServiceGetResponse, zFctOpcodeGasByOpcodeDailyServiceListData, @@ -1561,6 +1589,14 @@ import { zIntBlockProposerCanonicalServiceGetResponse, zIntBlockProposerCanonicalServiceListData, zIntBlockProposerCanonicalServiceListResponse, + zIntContractCreationServiceGetData, + zIntContractCreationServiceGetResponse, + zIntContractCreationServiceListData, + zIntContractCreationServiceListResponse, + zIntContractSelfdestructServiceGetData, + zIntContractSelfdestructServiceGetResponse, + zIntContractSelfdestructServiceListData, + zIntContractSelfdestructServiceListResponse, zIntContractStorageExpiry12mServiceGetData, zIntContractStorageExpiry12mServiceGetResponse, zIntContractStorageExpiry12mServiceListData, @@ -1641,10 +1677,10 @@ import { zIntEngineGetBlobsServiceGetResponse, zIntEngineGetBlobsServiceListData, zIntEngineGetBlobsServiceListResponse, - zIntEngineNewPayloadFastestServiceGetData, - zIntEngineNewPayloadFastestServiceGetResponse, - zIntEngineNewPayloadFastestServiceListData, - zIntEngineNewPayloadFastestServiceListResponse, + zIntEngineNewPayloadFastestExecutionByNodeClassServiceGetData, + zIntEngineNewPayloadFastestExecutionByNodeClassServiceGetResponse, + zIntEngineNewPayloadFastestExecutionByNodeClassServiceListData, + zIntEngineNewPayloadFastestExecutionByNodeClassServiceListResponse, zIntEngineNewPayloadServiceGetData, zIntEngineNewPayloadServiceGetResponse, zIntEngineNewPayloadServiceListData, @@ -1653,6 +1689,10 @@ import { zIntExecutionBlockByDateServiceGetResponse, zIntExecutionBlockByDateServiceListData, zIntExecutionBlockByDateServiceListResponse, + zIntStorageSelfdestructDiffsServiceGetData, + zIntStorageSelfdestructDiffsServiceGetResponse, + zIntStorageSelfdestructDiffsServiceListData, + zIntStorageSelfdestructDiffsServiceListResponse, zIntStorageSlotDiffByAddressSlotServiceGetData, zIntStorageSlotDiffByAddressSlotServiceGetResponse, zIntStorageSlotDiffByAddressSlotServiceListData, @@ -5162,6 +5202,44 @@ export const fctNodeActiveLast24hServiceGet = ( + options?: Options +) => + (options?.client ?? client).get< + FctNodeCpuUtilizationServiceListResponses, + FctNodeCpuUtilizationServiceListErrors, + ThrowOnError + >({ + requestValidator: async data => await zFctNodeCpuUtilizationServiceListData.parseAsync(data), + responseValidator: async data => await zFctNodeCpuUtilizationServiceListResponse.parseAsync(data), + url: '/api/v1/fct_node_cpu_utilization', + ...options, + }); + +/** + * Get record + * + * Retrieve a single record by wallclock_slot_start_date_time + */ +export const fctNodeCpuUtilizationServiceGet = ( + options: Options +) => + (options.client ?? client).get< + FctNodeCpuUtilizationServiceGetResponses, + FctNodeCpuUtilizationServiceGetErrors, + ThrowOnError + >({ + requestValidator: async data => await zFctNodeCpuUtilizationServiceGetData.parseAsync(data), + responseValidator: async data => await zFctNodeCpuUtilizationServiceGetResponse.parseAsync(data), + url: '/api/v1/fct_node_cpu_utilization/{wallclock_slot_start_date_time}', + ...options, + }); + /** * List records * @@ -6596,6 +6674,82 @@ export const intBlockProposerCanonicalServiceGet = ( + options?: Options +) => + (options?.client ?? client).get< + IntContractCreationServiceListResponses, + IntContractCreationServiceListErrors, + ThrowOnError + >({ + requestValidator: async data => await zIntContractCreationServiceListData.parseAsync(data), + responseValidator: async data => await zIntContractCreationServiceListResponse.parseAsync(data), + url: '/api/v1/int_contract_creation', + ...options, + }); + +/** + * Get record + * + * Retrieve a single record by block_number + */ +export const intContractCreationServiceGet = ( + options: Options +) => + (options.client ?? client).get< + IntContractCreationServiceGetResponses, + IntContractCreationServiceGetErrors, + ThrowOnError + >({ + requestValidator: async data => await zIntContractCreationServiceGetData.parseAsync(data), + responseValidator: async data => await zIntContractCreationServiceGetResponse.parseAsync(data), + url: '/api/v1/int_contract_creation/{block_number}', + ...options, + }); + +/** + * List records + * + * Retrieve paginated results with optional filtering + */ +export const intContractSelfdestructServiceList = ( + options?: Options +) => + (options?.client ?? client).get< + IntContractSelfdestructServiceListResponses, + IntContractSelfdestructServiceListErrors, + ThrowOnError + >({ + requestValidator: async data => await zIntContractSelfdestructServiceListData.parseAsync(data), + responseValidator: async data => await zIntContractSelfdestructServiceListResponse.parseAsync(data), + url: '/api/v1/int_contract_selfdestruct', + ...options, + }); + +/** + * Get record + * + * Retrieve a single record by block_number + */ +export const intContractSelfdestructServiceGet = ( + options: Options +) => + (options.client ?? client).get< + IntContractSelfdestructServiceGetResponses, + IntContractSelfdestructServiceGetErrors, + ThrowOnError + >({ + requestValidator: async data => await zIntContractSelfdestructServiceGetData.parseAsync(data), + responseValidator: async data => await zIntContractSelfdestructServiceGetResponse.parseAsync(data), + url: '/api/v1/int_contract_selfdestruct/{block_number}', + ...options, + }); + /** * List records * @@ -7392,17 +7546,19 @@ export const intEngineNewPayloadServiceGet = ( - options?: Options +export const intEngineNewPayloadFastestExecutionByNodeClassServiceList = ( + options?: Options ) => (options?.client ?? client).get< - IntEngineNewPayloadFastestServiceListResponses, - IntEngineNewPayloadFastestServiceListErrors, + IntEngineNewPayloadFastestExecutionByNodeClassServiceListResponses, + IntEngineNewPayloadFastestExecutionByNodeClassServiceListErrors, ThrowOnError >({ - requestValidator: async data => await zIntEngineNewPayloadFastestServiceListData.parseAsync(data), - responseValidator: async data => await zIntEngineNewPayloadFastestServiceListResponse.parseAsync(data), - url: '/api/v1/int_engine_new_payload_fastest', + requestValidator: async data => + await zIntEngineNewPayloadFastestExecutionByNodeClassServiceListData.parseAsync(data), + responseValidator: async data => + await zIntEngineNewPayloadFastestExecutionByNodeClassServiceListResponse.parseAsync(data), + url: '/api/v1/int_engine_new_payload_fastest_execution_by_node_class', ...options, }); @@ -7411,17 +7567,19 @@ export const intEngineNewPayloadFastestServiceList = ( - options: Options +export const intEngineNewPayloadFastestExecutionByNodeClassServiceGet = ( + options: Options ) => (options.client ?? client).get< - IntEngineNewPayloadFastestServiceGetResponses, - IntEngineNewPayloadFastestServiceGetErrors, + IntEngineNewPayloadFastestExecutionByNodeClassServiceGetResponses, + IntEngineNewPayloadFastestExecutionByNodeClassServiceGetErrors, ThrowOnError >({ - requestValidator: async data => await zIntEngineNewPayloadFastestServiceGetData.parseAsync(data), - responseValidator: async data => await zIntEngineNewPayloadFastestServiceGetResponse.parseAsync(data), - url: '/api/v1/int_engine_new_payload_fastest/{slot_start_date_time}', + requestValidator: async data => + await zIntEngineNewPayloadFastestExecutionByNodeClassServiceGetData.parseAsync(data), + responseValidator: async data => + await zIntEngineNewPayloadFastestExecutionByNodeClassServiceGetResponse.parseAsync(data), + url: '/api/v1/int_engine_new_payload_fastest_execution_by_node_class/{slot_start_date_time}', ...options, }); @@ -7463,6 +7621,44 @@ export const intExecutionBlockByDateServiceGet = ( + options?: Options +) => + (options?.client ?? client).get< + IntStorageSelfdestructDiffsServiceListResponses, + IntStorageSelfdestructDiffsServiceListErrors, + ThrowOnError + >({ + requestValidator: async data => await zIntStorageSelfdestructDiffsServiceListData.parseAsync(data), + responseValidator: async data => await zIntStorageSelfdestructDiffsServiceListResponse.parseAsync(data), + url: '/api/v1/int_storage_selfdestruct_diffs', + ...options, + }); + +/** + * Get record + * + * Retrieve a single record by block_number + */ +export const intStorageSelfdestructDiffsServiceGet = ( + options: Options +) => + (options.client ?? client).get< + IntStorageSelfdestructDiffsServiceGetResponses, + IntStorageSelfdestructDiffsServiceGetErrors, + ThrowOnError + >({ + requestValidator: async data => await zIntStorageSelfdestructDiffsServiceGetData.parseAsync(data), + responseValidator: async data => await zIntStorageSelfdestructDiffsServiceGetResponse.parseAsync(data), + url: '/api/v1/int_storage_selfdestruct_diffs/{block_number}', + ...options, + }); + /** * List records * diff --git a/src/api/types.gen.ts b/src/api/types.gen.ts index 6c96b1476..4c7cd6b42 100644 --- a/src/api/types.gen.ts +++ b/src/api/types.gen.ts @@ -4560,6 +4560,65 @@ export type FctNodeActiveLast24h = { username?: string; }; +export type FctNodeCpuUtilization = { + /** + * Client type: CL or EL + */ + client_type?: string; + /** + * Maximum CPU core utilization percentage (100pct = 1 core) + */ + max_core_pct?: number; + /** + * Maximum single core utilization percentage (0-100pct) + */ + max_single_core_pct?: number; + /** + * Mean CPU core utilization percentage (100pct = 1 core) + */ + mean_core_pct?: number; + /** + * Name of the observoor client that collected the data + */ + meta_client_name?: string; + /** + * Ethereum network name + */ + meta_network_name?: string; + /** + * Minimum CPU core utilization percentage (100pct = 1 core) + */ + min_core_pct?: number; + /** + * Node classification for filtering (e.g. eip7870) + */ + node_class?: string; + /** + * Process ID of the monitored client + */ + pid?: number; + /** + * Total system CPU cores + */ + system_cores?: number; + /** + * Timestamp when the record was last updated + */ + updated_date_time?: number; + /** + * The wallclock slot number + */ + wallclock_slot?: number; + /** + * The wall clock time when the slot started + */ + wallclock_slot_start_date_time?: number; + /** + * Start of the sub-slot aggregation window + */ + window_start?: number; +}; + export type FctOpcodeGasByOpcodeDaily = { /** * Average executions per block @@ -6149,6 +6208,13 @@ export type GetFctNodeActiveLast24hResponse = { item?: FctNodeActiveLast24h; }; +/** + * Response for getting a single fct_node_cpu_utilization record + */ +export type GetFctNodeCpuUtilizationResponse = { + item?: FctNodeCpuUtilization; +}; + /** * Response for getting a single fct_opcode_gas_by_opcode_daily record */ @@ -6415,6 +6481,20 @@ export type GetIntBlockProposerCanonicalResponse = { item?: IntBlockProposerCanonical; }; +/** + * Response for getting a single int_contract_creation record + */ +export type GetIntContractCreationResponse = { + item?: IntContractCreation; +}; + +/** + * Response for getting a single int_contract_selfdestruct record + */ +export type GetIntContractSelfdestructResponse = { + item?: IntContractSelfdestruct; +}; + /** * Response for getting a single int_contract_storage_expiry_1m record */ @@ -6556,10 +6636,10 @@ export type GetIntEngineGetBlobsResponse = { }; /** - * Response for getting a single int_engine_new_payload_fastest record + * Response for getting a single int_engine_new_payload_fastest_execution_by_node_class record */ -export type GetIntEngineNewPayloadFastestResponse = { - item?: IntEngineNewPayloadFastest; +export type GetIntEngineNewPayloadFastestExecutionByNodeClassResponse = { + item?: IntEngineNewPayloadFastestExecutionByNodeClass; }; /** @@ -6576,6 +6656,13 @@ export type GetIntExecutionBlockByDateResponse = { item?: IntExecutionBlockByDate; }; +/** + * Response for getting a single int_storage_selfdestruct_diffs record + */ +export type GetIntStorageSelfdestructDiffsResponse = { + item?: IntStorageSelfdestructDiffs; +}; + /** * Response for getting a single int_storage_slot_diff_by_address_slot record */ @@ -7355,6 +7442,96 @@ export type IntBlockProposerCanonical = { updated_date_time?: number; }; +export type IntContractCreation = { + /** + * Block where contract was created + */ + block_number?: number; + /** + * Address of created contract + */ + contract_address?: string; + /** + * Address that deployed the contract + */ + deployer?: string; + /** + * Factory contract address if applicable + */ + factory?: string; + /** + * Hash of the initialization code + */ + init_code_hash?: string; + /** + * Position within transaction + */ + internal_index?: number; + /** + * Transaction hash + */ + transaction_hash?: string; + /** + * Position in block + */ + transaction_index?: number; + /** + * Timestamp when the record was last updated + */ + updated_date_time?: number; +}; + +export type IntContractSelfdestruct = { + /** + * Contract that was destroyed + */ + address?: string; + /** + * Address receiving the ETH + */ + beneficiary?: string; + /** + * Block where SELFDESTRUCT occurred + */ + block_number?: number; + /** + * Block where contract was created (if known) + */ + creation_block?: number | null; + /** + * Transaction that created the contract (if known) + */ + creation_transaction_hash?: string | null; + /** + * True if contract was created and destroyed in the same transaction - storage always cleared per EIP-6780 + */ + ephemeral?: boolean; + /** + * Position within transaction traces + */ + internal_index?: number; + /** + * True if storage was cleared (pre-Shanghai OR ephemeral) + */ + storage_cleared?: boolean; + /** + * Transaction hash + */ + transaction_hash?: string; + /** + * Position in block + */ + transaction_index?: number; + /** + * Timestamp when the record was last updated + */ + updated_date_time?: number; + /** + * Amount of ETH sent to beneficiary + */ + value_transferred?: string; +}; + export type IntContractStorageExpiry1m = { /** * Count of slots in the contract at expiry time @@ -8426,7 +8603,7 @@ export type IntEngineNewPayload = { validation_error?: string | null; }; -export type IntEngineNewPayloadFastest = { +export type IntEngineNewPayloadFastestExecutionByNodeClass = { /** * Execution block hash (hex encoded with 0x prefix) */ @@ -8488,6 +8665,45 @@ export type IntExecutionBlockByDate = { updated_date_time?: number; }; +export type IntStorageSelfdestructDiffs = { + /** + * Contract address that was selfdestructed + */ + address?: string; + /** + * Block where SELFDESTRUCT occurred + */ + block_number?: number; + /** + * Value before clearing (last known value) + */ + from_value?: string; + /** + * Internal index of the SELFDESTRUCT trace + */ + internal_index?: number; + /** + * Storage slot key being cleared + */ + slot?: string; + /** + * Value after clearing (always 0x00...00) + */ + to_value?: string; + /** + * Transaction hash of the SELFDESTRUCT + */ + transaction_hash?: string; + /** + * Transaction index within the block + */ + transaction_index?: number; + /** + * Timestamp when the record was last updated + */ + updated_date_time?: number; +}; + export type IntStorageSlotDiff = { /** * The contract address @@ -10489,6 +10705,20 @@ export type ListFctNodeActiveLast24hResponse = { next_page_token?: string; }; +/** + * Response for listing fct_node_cpu_utilization records + */ +export type ListFctNodeCpuUtilizationResponse = { + /** + * The list of fct_node_cpu_utilization. + */ + fct_node_cpu_utilization?: Array; + /** + * A token, which can be sent as `page_token` to retrieve the next page. If this field is omitted, there are no subsequent pages. + */ + next_page_token?: string; +}; + /** * Response for listing fct_opcode_gas_by_opcode_daily records */ @@ -11021,6 +11251,34 @@ export type ListIntBlockProposerCanonicalResponse = { next_page_token?: string; }; +/** + * Response for listing int_contract_creation records + */ +export type ListIntContractCreationResponse = { + /** + * The list of int_contract_creation. + */ + int_contract_creation?: Array; + /** + * A token, which can be sent as `page_token` to retrieve the next page. If this field is omitted, there are no subsequent pages. + */ + next_page_token?: string; +}; + +/** + * Response for listing int_contract_selfdestruct records + */ +export type ListIntContractSelfdestructResponse = { + /** + * The list of int_contract_selfdestruct. + */ + int_contract_selfdestruct?: Array; + /** + * A token, which can be sent as `page_token` to retrieve the next page. If this field is omitted, there are no subsequent pages. + */ + next_page_token?: string; +}; + /** * Response for listing int_contract_storage_expiry_1m records */ @@ -11302,13 +11560,13 @@ export type ListIntEngineGetBlobsResponse = { }; /** - * Response for listing int_engine_new_payload_fastest records + * Response for listing int_engine_new_payload_fastest_execution_by_node_class records */ -export type ListIntEngineNewPayloadFastestResponse = { +export type ListIntEngineNewPayloadFastestExecutionByNodeClassResponse = { /** - * The list of int_engine_new_payload_fastest. + * The list of int_engine_new_payload_fastest_execution_by_node_class. */ - int_engine_new_payload_fastest?: Array; + int_engine_new_payload_fastest_execution_by_node_class?: Array; /** * A token, which can be sent as `page_token` to retrieve the next page. If this field is omitted, there are no subsequent pages. */ @@ -11343,6 +11601,20 @@ export type ListIntExecutionBlockByDateResponse = { next_page_token?: string; }; +/** + * Response for listing int_storage_selfdestruct_diffs records + */ +export type ListIntStorageSelfdestructDiffsResponse = { + /** + * The list of int_storage_selfdestruct_diffs. + */ + int_storage_selfdestruct_diffs?: Array; + /** + * A token, which can be sent as `page_token` to retrieve the next page. If this field is omitted, there are no subsequent pages. + */ + next_page_token?: string; +}; + /** * Response for listing int_storage_slot_diff_by_address_slot records */ @@ -54833,82 +55105,554 @@ export type FctNodeActiveLast24hServiceGetResponses = { export type FctNodeActiveLast24hServiceGetResponse = FctNodeActiveLast24hServiceGetResponses[keyof FctNodeActiveLast24hServiceGetResponses]; -export type FctOpcodeGasByOpcodeDailyServiceListData = { +export type FctNodeCpuUtilizationServiceListData = { body?: never; path?: never; query?: { /** - * Start of the day period (filter: eq) + * The wall clock time when the slot started (filter: eq) */ - day_start_date_eq?: string; + wallclock_slot_start_date_time_eq?: number; /** - * Start of the day period (filter: ne) + * The wall clock time when the slot started (filter: ne) */ - day_start_date_ne?: string; + wallclock_slot_start_date_time_ne?: number; /** - * Start of the day period (filter: contains) + * The wall clock time when the slot started (filter: lt) */ - day_start_date_contains?: string; + wallclock_slot_start_date_time_lt?: number; /** - * Start of the day period (filter: starts_with) + * The wall clock time when the slot started (filter: lte) */ - day_start_date_starts_with?: string; + wallclock_slot_start_date_time_lte?: number; /** - * Start of the day period (filter: ends_with) + * The wall clock time when the slot started (filter: gt) */ - day_start_date_ends_with?: string; + wallclock_slot_start_date_time_gt?: number; /** - * Start of the day period (filter: like) + * The wall clock time when the slot started (filter: gte) */ - day_start_date_like?: string; + wallclock_slot_start_date_time_gte?: number; /** - * Start of the day period (filter: not_like) + * The wall clock time when the slot started (filter: between_min) */ - day_start_date_not_like?: string; + wallclock_slot_start_date_time_between_min?: number; /** - * Start of the day period (filter: in_values) (comma-separated list) + * The wall clock time when the slot started (filter: between_max_value) */ - day_start_date_in_values?: string; + wallclock_slot_start_date_time_between_max_value?: number; /** - * Start of the day period (filter: not_in_values) (comma-separated list) + * The wall clock time when the slot started (filter: in_values) (comma-separated list) */ - day_start_date_not_in_values?: string; + wallclock_slot_start_date_time_in_values?: string; /** - * The EVM opcode name (e.g., SLOAD, ADD, CALL) (filter: eq) + * The wall clock time when the slot started (filter: not_in_values) (comma-separated list) */ - opcode_eq?: string; + wallclock_slot_start_date_time_not_in_values?: string; /** - * The EVM opcode name (e.g., SLOAD, ADD, CALL) (filter: ne) + * Name of the observoor client that collected the data (filter: eq) */ - opcode_ne?: string; + meta_client_name_eq?: string; /** - * The EVM opcode name (e.g., SLOAD, ADD, CALL) (filter: contains) + * Name of the observoor client that collected the data (filter: ne) */ - opcode_contains?: string; + meta_client_name_ne?: string; /** - * The EVM opcode name (e.g., SLOAD, ADD, CALL) (filter: starts_with) + * Name of the observoor client that collected the data (filter: contains) */ - opcode_starts_with?: string; + meta_client_name_contains?: string; /** - * The EVM opcode name (e.g., SLOAD, ADD, CALL) (filter: ends_with) + * Name of the observoor client that collected the data (filter: starts_with) */ - opcode_ends_with?: string; + meta_client_name_starts_with?: string; /** - * The EVM opcode name (e.g., SLOAD, ADD, CALL) (filter: like) + * Name of the observoor client that collected the data (filter: ends_with) */ - opcode_like?: string; + meta_client_name_ends_with?: string; /** - * The EVM opcode name (e.g., SLOAD, ADD, CALL) (filter: not_like) + * Name of the observoor client that collected the data (filter: like) */ - opcode_not_like?: string; + meta_client_name_like?: string; /** - * The EVM opcode name (e.g., SLOAD, ADD, CALL) (filter: in_values) (comma-separated list) + * Name of the observoor client that collected the data (filter: not_like) */ - opcode_in_values?: string; + meta_client_name_not_like?: string; /** - * The EVM opcode name (e.g., SLOAD, ADD, CALL) (filter: not_in_values) (comma-separated list) + * Name of the observoor client that collected the data (filter: in_values) (comma-separated list) */ - opcode_not_in_values?: string; + meta_client_name_in_values?: string; + /** + * Name of the observoor client that collected the data (filter: not_in_values) (comma-separated list) + */ + meta_client_name_not_in_values?: string; + /** + * Client type: CL or EL (filter: eq) + */ + client_type_eq?: string; + /** + * Client type: CL or EL (filter: ne) + */ + client_type_ne?: string; + /** + * Client type: CL or EL (filter: contains) + */ + client_type_contains?: string; + /** + * Client type: CL or EL (filter: starts_with) + */ + client_type_starts_with?: string; + /** + * Client type: CL or EL (filter: ends_with) + */ + client_type_ends_with?: string; + /** + * Client type: CL or EL (filter: like) + */ + client_type_like?: string; + /** + * Client type: CL or EL (filter: not_like) + */ + client_type_not_like?: string; + /** + * Client type: CL or EL (filter: in_values) (comma-separated list) + */ + client_type_in_values?: string; + /** + * Client type: CL or EL (filter: not_in_values) (comma-separated list) + */ + client_type_not_in_values?: string; + /** + * Process ID of the monitored client (filter: eq) + */ + pid_eq?: number; + /** + * Process ID of the monitored client (filter: ne) + */ + pid_ne?: number; + /** + * Process ID of the monitored client (filter: lt) + */ + pid_lt?: number; + /** + * Process ID of the monitored client (filter: lte) + */ + pid_lte?: number; + /** + * Process ID of the monitored client (filter: gt) + */ + pid_gt?: number; + /** + * Process ID of the monitored client (filter: gte) + */ + pid_gte?: number; + /** + * Process ID of the monitored client (filter: between_min) + */ + pid_between_min?: number; + /** + * Process ID of the monitored client (filter: between_max_value) + */ + pid_between_max_value?: number; + /** + * Process ID of the monitored client (filter: in_values) (comma-separated list) + */ + pid_in_values?: string; + /** + * Process ID of the monitored client (filter: not_in_values) (comma-separated list) + */ + pid_not_in_values?: string; + /** + * Start of the sub-slot aggregation window (filter: eq) + */ + window_start_eq?: number; + /** + * Start of the sub-slot aggregation window (filter: ne) + */ + window_start_ne?: number; + /** + * Start of the sub-slot aggregation window (filter: lt) + */ + window_start_lt?: number; + /** + * Start of the sub-slot aggregation window (filter: lte) + */ + window_start_lte?: number; + /** + * Start of the sub-slot aggregation window (filter: gt) + */ + window_start_gt?: number; + /** + * Start of the sub-slot aggregation window (filter: gte) + */ + window_start_gte?: number; + /** + * Start of the sub-slot aggregation window (filter: between_min) + */ + window_start_between_min?: number; + /** + * Start of the sub-slot aggregation window (filter: between_max_value) + */ + window_start_between_max_value?: number; + /** + * Start of the sub-slot aggregation window (filter: in_values) (comma-separated list) + */ + window_start_in_values?: string; + /** + * Start of the sub-slot aggregation window (filter: not_in_values) (comma-separated list) + */ + window_start_not_in_values?: string; + /** + * Timestamp when the record was last updated (filter: eq) + */ + updated_date_time_eq?: number; + /** + * Timestamp when the record was last updated (filter: ne) + */ + updated_date_time_ne?: number; + /** + * Timestamp when the record was last updated (filter: lt) + */ + updated_date_time_lt?: number; + /** + * Timestamp when the record was last updated (filter: lte) + */ + updated_date_time_lte?: number; + /** + * Timestamp when the record was last updated (filter: gt) + */ + updated_date_time_gt?: number; + /** + * Timestamp when the record was last updated (filter: gte) + */ + updated_date_time_gte?: number; + /** + * Timestamp when the record was last updated (filter: between_min) + */ + updated_date_time_between_min?: number; + /** + * Timestamp when the record was last updated (filter: between_max_value) + */ + updated_date_time_between_max_value?: number; + /** + * Timestamp when the record was last updated (filter: in_values) (comma-separated list) + */ + updated_date_time_in_values?: string; + /** + * Timestamp when the record was last updated (filter: not_in_values) (comma-separated list) + */ + updated_date_time_not_in_values?: string; + /** + * The wallclock slot number (filter: eq) + */ + wallclock_slot_eq?: number; + /** + * The wallclock slot number (filter: ne) + */ + wallclock_slot_ne?: number; + /** + * The wallclock slot number (filter: lt) + */ + wallclock_slot_lt?: number; + /** + * The wallclock slot number (filter: lte) + */ + wallclock_slot_lte?: number; + /** + * The wallclock slot number (filter: gt) + */ + wallclock_slot_gt?: number; + /** + * The wallclock slot number (filter: gte) + */ + wallclock_slot_gte?: number; + /** + * The wallclock slot number (filter: between_min) + */ + wallclock_slot_between_min?: number; + /** + * The wallclock slot number (filter: between_max_value) + */ + wallclock_slot_between_max_value?: number; + /** + * The wallclock slot number (filter: in_values) (comma-separated list) + */ + wallclock_slot_in_values?: string; + /** + * The wallclock slot number (filter: not_in_values) (comma-separated list) + */ + wallclock_slot_not_in_values?: string; + /** + * Ethereum network name (filter: eq) + */ + meta_network_name_eq?: string; + /** + * Ethereum network name (filter: ne) + */ + meta_network_name_ne?: string; + /** + * Ethereum network name (filter: contains) + */ + meta_network_name_contains?: string; + /** + * Ethereum network name (filter: starts_with) + */ + meta_network_name_starts_with?: string; + /** + * Ethereum network name (filter: ends_with) + */ + meta_network_name_ends_with?: string; + /** + * Ethereum network name (filter: like) + */ + meta_network_name_like?: string; + /** + * Ethereum network name (filter: not_like) + */ + meta_network_name_not_like?: string; + /** + * Ethereum network name (filter: in_values) (comma-separated list) + */ + meta_network_name_in_values?: string; + /** + * Ethereum network name (filter: not_in_values) (comma-separated list) + */ + meta_network_name_not_in_values?: string; + /** + * Total system CPU cores (filter: eq) + */ + system_cores_eq?: number; + /** + * Total system CPU cores (filter: ne) + */ + system_cores_ne?: number; + /** + * Total system CPU cores (filter: lt) + */ + system_cores_lt?: number; + /** + * Total system CPU cores (filter: lte) + */ + system_cores_lte?: number; + /** + * Total system CPU cores (filter: gt) + */ + system_cores_gt?: number; + /** + * Total system CPU cores (filter: gte) + */ + system_cores_gte?: number; + /** + * Total system CPU cores (filter: between_min) + */ + system_cores_between_min?: number; + /** + * Total system CPU cores (filter: between_max_value) + */ + system_cores_between_max_value?: number; + /** + * Total system CPU cores (filter: in_values) (comma-separated list) + */ + system_cores_in_values?: string; + /** + * Total system CPU cores (filter: not_in_values) (comma-separated list) + */ + system_cores_not_in_values?: string; + /** + * Filter mean_core_pct using value + */ + mean_core_pct_value?: number; + /** + * Filter min_core_pct using value + */ + min_core_pct_value?: number; + /** + * Filter max_core_pct using value + */ + max_core_pct_value?: number; + /** + * Filter max_single_core_pct using value + */ + max_single_core_pct_value?: number; + /** + * Node classification for filtering (e.g. eip7870) (filter: eq) + */ + node_class_eq?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: ne) + */ + node_class_ne?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: contains) + */ + node_class_contains?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: starts_with) + */ + node_class_starts_with?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: ends_with) + */ + node_class_ends_with?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: like) + */ + node_class_like?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: not_like) + */ + node_class_not_like?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: in_values) (comma-separated list) + */ + node_class_in_values?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: not_in_values) (comma-separated list) + */ + node_class_not_in_values?: string; + /** + * The maximum number of fct_node_cpu_utilization to return. If unspecified, at most 100 items will be returned. The maximum value is 10000; values above 10000 will be coerced to 10000. + */ + page_size?: number; + /** + * A page token, received from a previous `ListFctNodeCpuUtilization` call. Provide this to retrieve the subsequent page. + */ + page_token?: string; + /** + * The order of results. Format: comma-separated list of fields. Example: "foo,bar" or "foo desc,bar" for descending order on foo. If unspecified, results will be returned in the default order. + */ + order_by?: string; + }; + url: '/api/v1/fct_node_cpu_utilization'; +}; + +export type FctNodeCpuUtilizationServiceListErrors = { + /** + * Default error response + */ + default: Status; +}; + +export type FctNodeCpuUtilizationServiceListError = + FctNodeCpuUtilizationServiceListErrors[keyof FctNodeCpuUtilizationServiceListErrors]; + +export type FctNodeCpuUtilizationServiceListResponses = { + /** + * OK + */ + 200: ListFctNodeCpuUtilizationResponse; +}; + +export type FctNodeCpuUtilizationServiceListResponse = + FctNodeCpuUtilizationServiceListResponses[keyof FctNodeCpuUtilizationServiceListResponses]; + +export type FctNodeCpuUtilizationServiceGetData = { + body?: never; + path: { + /** + * The wall clock time when the slot started + */ + wallclock_slot_start_date_time: number; + }; + query?: never; + url: '/api/v1/fct_node_cpu_utilization/{wallclock_slot_start_date_time}'; +}; + +export type FctNodeCpuUtilizationServiceGetErrors = { + /** + * Default error response + */ + default: Status; +}; + +export type FctNodeCpuUtilizationServiceGetError = + FctNodeCpuUtilizationServiceGetErrors[keyof FctNodeCpuUtilizationServiceGetErrors]; + +export type FctNodeCpuUtilizationServiceGetResponses = { + /** + * OK + */ + 200: GetFctNodeCpuUtilizationResponse; +}; + +export type FctNodeCpuUtilizationServiceGetResponse = + FctNodeCpuUtilizationServiceGetResponses[keyof FctNodeCpuUtilizationServiceGetResponses]; + +export type FctOpcodeGasByOpcodeDailyServiceListData = { + body?: never; + path?: never; + query?: { + /** + * Start of the day period (filter: eq) + */ + day_start_date_eq?: string; + /** + * Start of the day period (filter: ne) + */ + day_start_date_ne?: string; + /** + * Start of the day period (filter: contains) + */ + day_start_date_contains?: string; + /** + * Start of the day period (filter: starts_with) + */ + day_start_date_starts_with?: string; + /** + * Start of the day period (filter: ends_with) + */ + day_start_date_ends_with?: string; + /** + * Start of the day period (filter: like) + */ + day_start_date_like?: string; + /** + * Start of the day period (filter: not_like) + */ + day_start_date_not_like?: string; + /** + * Start of the day period (filter: in_values) (comma-separated list) + */ + day_start_date_in_values?: string; + /** + * Start of the day period (filter: not_in_values) (comma-separated list) + */ + day_start_date_not_in_values?: string; + /** + * The EVM opcode name (e.g., SLOAD, ADD, CALL) (filter: eq) + */ + opcode_eq?: string; + /** + * The EVM opcode name (e.g., SLOAD, ADD, CALL) (filter: ne) + */ + opcode_ne?: string; + /** + * The EVM opcode name (e.g., SLOAD, ADD, CALL) (filter: contains) + */ + opcode_contains?: string; + /** + * The EVM opcode name (e.g., SLOAD, ADD, CALL) (filter: starts_with) + */ + opcode_starts_with?: string; + /** + * The EVM opcode name (e.g., SLOAD, ADD, CALL) (filter: ends_with) + */ + opcode_ends_with?: string; + /** + * The EVM opcode name (e.g., SLOAD, ADD, CALL) (filter: like) + */ + opcode_like?: string; + /** + * The EVM opcode name (e.g., SLOAD, ADD, CALL) (filter: not_like) + */ + opcode_not_like?: string; + /** + * The EVM opcode name (e.g., SLOAD, ADD, CALL) (filter: in_values) (comma-separated list) + */ + opcode_in_values?: string; + /** + * The EVM opcode name (e.g., SLOAD, ADD, CALL) (filter: not_in_values) (comma-separated list) + */ + opcode_not_in_values?: string; /** * Timestamp when the record was last updated (filter: eq) */ @@ -69723,6 +70467,886 @@ export type IntBlockProposerCanonicalServiceGetResponses = { export type IntBlockProposerCanonicalServiceGetResponse = IntBlockProposerCanonicalServiceGetResponses[keyof IntBlockProposerCanonicalServiceGetResponses]; +export type IntContractCreationServiceListData = { + body?: never; + path?: never; + query?: { + /** + * Block where contract was created (filter: eq) + */ + block_number_eq?: number; + /** + * Block where contract was created (filter: ne) + */ + block_number_ne?: number; + /** + * Block where contract was created (filter: lt) + */ + block_number_lt?: number; + /** + * Block where contract was created (filter: lte) + */ + block_number_lte?: number; + /** + * Block where contract was created (filter: gt) + */ + block_number_gt?: number; + /** + * Block where contract was created (filter: gte) + */ + block_number_gte?: number; + /** + * Block where contract was created (filter: between_min) + */ + block_number_between_min?: number; + /** + * Block where contract was created (filter: between_max_value) + */ + block_number_between_max_value?: number; + /** + * Block where contract was created (filter: in_values) (comma-separated list) + */ + block_number_in_values?: string; + /** + * Block where contract was created (filter: not_in_values) (comma-separated list) + */ + block_number_not_in_values?: string; + /** + * Address of created contract (filter: eq) + */ + contract_address_eq?: string; + /** + * Address of created contract (filter: ne) + */ + contract_address_ne?: string; + /** + * Address of created contract (filter: contains) + */ + contract_address_contains?: string; + /** + * Address of created contract (filter: starts_with) + */ + contract_address_starts_with?: string; + /** + * Address of created contract (filter: ends_with) + */ + contract_address_ends_with?: string; + /** + * Address of created contract (filter: like) + */ + contract_address_like?: string; + /** + * Address of created contract (filter: not_like) + */ + contract_address_not_like?: string; + /** + * Address of created contract (filter: in_values) (comma-separated list) + */ + contract_address_in_values?: string; + /** + * Address of created contract (filter: not_in_values) (comma-separated list) + */ + contract_address_not_in_values?: string; + /** + * Transaction hash (filter: eq) + */ + transaction_hash_eq?: string; + /** + * Transaction hash (filter: ne) + */ + transaction_hash_ne?: string; + /** + * Transaction hash (filter: contains) + */ + transaction_hash_contains?: string; + /** + * Transaction hash (filter: starts_with) + */ + transaction_hash_starts_with?: string; + /** + * Transaction hash (filter: ends_with) + */ + transaction_hash_ends_with?: string; + /** + * Transaction hash (filter: like) + */ + transaction_hash_like?: string; + /** + * Transaction hash (filter: not_like) + */ + transaction_hash_not_like?: string; + /** + * Transaction hash (filter: in_values) (comma-separated list) + */ + transaction_hash_in_values?: string; + /** + * Transaction hash (filter: not_in_values) (comma-separated list) + */ + transaction_hash_not_in_values?: string; + /** + * Timestamp when the record was last updated (filter: eq) + */ + updated_date_time_eq?: number; + /** + * Timestamp when the record was last updated (filter: ne) + */ + updated_date_time_ne?: number; + /** + * Timestamp when the record was last updated (filter: lt) + */ + updated_date_time_lt?: number; + /** + * Timestamp when the record was last updated (filter: lte) + */ + updated_date_time_lte?: number; + /** + * Timestamp when the record was last updated (filter: gt) + */ + updated_date_time_gt?: number; + /** + * Timestamp when the record was last updated (filter: gte) + */ + updated_date_time_gte?: number; + /** + * Timestamp when the record was last updated (filter: between_min) + */ + updated_date_time_between_min?: number; + /** + * Timestamp when the record was last updated (filter: between_max_value) + */ + updated_date_time_between_max_value?: number; + /** + * Timestamp when the record was last updated (filter: in_values) (comma-separated list) + */ + updated_date_time_in_values?: string; + /** + * Timestamp when the record was last updated (filter: not_in_values) (comma-separated list) + */ + updated_date_time_not_in_values?: string; + /** + * Position in block (filter: eq) + */ + transaction_index_eq?: number; + /** + * Position in block (filter: ne) + */ + transaction_index_ne?: number; + /** + * Position in block (filter: lt) + */ + transaction_index_lt?: number; + /** + * Position in block (filter: lte) + */ + transaction_index_lte?: number; + /** + * Position in block (filter: gt) + */ + transaction_index_gt?: number; + /** + * Position in block (filter: gte) + */ + transaction_index_gte?: number; + /** + * Position in block (filter: between_min) + */ + transaction_index_between_min?: number; + /** + * Position in block (filter: between_max_value) + */ + transaction_index_between_max_value?: number; + /** + * Position in block (filter: in_values) (comma-separated list) + */ + transaction_index_in_values?: string; + /** + * Position in block (filter: not_in_values) (comma-separated list) + */ + transaction_index_not_in_values?: string; + /** + * Position within transaction (filter: eq) + */ + internal_index_eq?: number; + /** + * Position within transaction (filter: ne) + */ + internal_index_ne?: number; + /** + * Position within transaction (filter: lt) + */ + internal_index_lt?: number; + /** + * Position within transaction (filter: lte) + */ + internal_index_lte?: number; + /** + * Position within transaction (filter: gt) + */ + internal_index_gt?: number; + /** + * Position within transaction (filter: gte) + */ + internal_index_gte?: number; + /** + * Position within transaction (filter: between_min) + */ + internal_index_between_min?: number; + /** + * Position within transaction (filter: between_max_value) + */ + internal_index_between_max_value?: number; + /** + * Position within transaction (filter: in_values) (comma-separated list) + */ + internal_index_in_values?: string; + /** + * Position within transaction (filter: not_in_values) (comma-separated list) + */ + internal_index_not_in_values?: string; + /** + * Address that deployed the contract (filter: eq) + */ + deployer_eq?: string; + /** + * Address that deployed the contract (filter: ne) + */ + deployer_ne?: string; + /** + * Address that deployed the contract (filter: contains) + */ + deployer_contains?: string; + /** + * Address that deployed the contract (filter: starts_with) + */ + deployer_starts_with?: string; + /** + * Address that deployed the contract (filter: ends_with) + */ + deployer_ends_with?: string; + /** + * Address that deployed the contract (filter: like) + */ + deployer_like?: string; + /** + * Address that deployed the contract (filter: not_like) + */ + deployer_not_like?: string; + /** + * Address that deployed the contract (filter: in_values) (comma-separated list) + */ + deployer_in_values?: string; + /** + * Address that deployed the contract (filter: not_in_values) (comma-separated list) + */ + deployer_not_in_values?: string; + /** + * Factory contract address if applicable (filter: eq) + */ + factory_eq?: string; + /** + * Factory contract address if applicable (filter: ne) + */ + factory_ne?: string; + /** + * Factory contract address if applicable (filter: contains) + */ + factory_contains?: string; + /** + * Factory contract address if applicable (filter: starts_with) + */ + factory_starts_with?: string; + /** + * Factory contract address if applicable (filter: ends_with) + */ + factory_ends_with?: string; + /** + * Factory contract address if applicable (filter: like) + */ + factory_like?: string; + /** + * Factory contract address if applicable (filter: not_like) + */ + factory_not_like?: string; + /** + * Factory contract address if applicable (filter: in_values) (comma-separated list) + */ + factory_in_values?: string; + /** + * Factory contract address if applicable (filter: not_in_values) (comma-separated list) + */ + factory_not_in_values?: string; + /** + * Hash of the initialization code (filter: eq) + */ + init_code_hash_eq?: string; + /** + * Hash of the initialization code (filter: ne) + */ + init_code_hash_ne?: string; + /** + * Hash of the initialization code (filter: contains) + */ + init_code_hash_contains?: string; + /** + * Hash of the initialization code (filter: starts_with) + */ + init_code_hash_starts_with?: string; + /** + * Hash of the initialization code (filter: ends_with) + */ + init_code_hash_ends_with?: string; + /** + * Hash of the initialization code (filter: like) + */ + init_code_hash_like?: string; + /** + * Hash of the initialization code (filter: not_like) + */ + init_code_hash_not_like?: string; + /** + * Hash of the initialization code (filter: in_values) (comma-separated list) + */ + init_code_hash_in_values?: string; + /** + * Hash of the initialization code (filter: not_in_values) (comma-separated list) + */ + init_code_hash_not_in_values?: string; + /** + * The maximum number of int_contract_creation to return. If unspecified, at most 100 items will be returned. The maximum value is 10000; values above 10000 will be coerced to 10000. + */ + page_size?: number; + /** + * A page token, received from a previous `ListIntContractCreation` call. Provide this to retrieve the subsequent page. + */ + page_token?: string; + /** + * The order of results. Format: comma-separated list of fields. Example: "foo,bar" or "foo desc,bar" for descending order on foo. If unspecified, results will be returned in the default order. + */ + order_by?: string; + }; + url: '/api/v1/int_contract_creation'; +}; + +export type IntContractCreationServiceListErrors = { + /** + * Default error response + */ + default: Status; +}; + +export type IntContractCreationServiceListError = + IntContractCreationServiceListErrors[keyof IntContractCreationServiceListErrors]; + +export type IntContractCreationServiceListResponses = { + /** + * OK + */ + 200: ListIntContractCreationResponse; +}; + +export type IntContractCreationServiceListResponse = + IntContractCreationServiceListResponses[keyof IntContractCreationServiceListResponses]; + +export type IntContractCreationServiceGetData = { + body?: never; + path: { + /** + * Block where contract was created + */ + block_number: number; + }; + query?: never; + url: '/api/v1/int_contract_creation/{block_number}'; +}; + +export type IntContractCreationServiceGetErrors = { + /** + * Default error response + */ + default: Status; +}; + +export type IntContractCreationServiceGetError = + IntContractCreationServiceGetErrors[keyof IntContractCreationServiceGetErrors]; + +export type IntContractCreationServiceGetResponses = { + /** + * OK + */ + 200: GetIntContractCreationResponse; +}; + +export type IntContractCreationServiceGetResponse = + IntContractCreationServiceGetResponses[keyof IntContractCreationServiceGetResponses]; + +export type IntContractSelfdestructServiceListData = { + body?: never; + path?: never; + query?: { + /** + * Block where SELFDESTRUCT occurred (filter: eq) + */ + block_number_eq?: number; + /** + * Block where SELFDESTRUCT occurred (filter: ne) + */ + block_number_ne?: number; + /** + * Block where SELFDESTRUCT occurred (filter: lt) + */ + block_number_lt?: number; + /** + * Block where SELFDESTRUCT occurred (filter: lte) + */ + block_number_lte?: number; + /** + * Block where SELFDESTRUCT occurred (filter: gt) + */ + block_number_gt?: number; + /** + * Block where SELFDESTRUCT occurred (filter: gte) + */ + block_number_gte?: number; + /** + * Block where SELFDESTRUCT occurred (filter: between_min) + */ + block_number_between_min?: number; + /** + * Block where SELFDESTRUCT occurred (filter: between_max_value) + */ + block_number_between_max_value?: number; + /** + * Block where SELFDESTRUCT occurred (filter: in_values) (comma-separated list) + */ + block_number_in_values?: string; + /** + * Block where SELFDESTRUCT occurred (filter: not_in_values) (comma-separated list) + */ + block_number_not_in_values?: string; + /** + * Position in block (filter: eq) + */ + transaction_index_eq?: number; + /** + * Position in block (filter: ne) + */ + transaction_index_ne?: number; + /** + * Position in block (filter: lt) + */ + transaction_index_lt?: number; + /** + * Position in block (filter: lte) + */ + transaction_index_lte?: number; + /** + * Position in block (filter: gt) + */ + transaction_index_gt?: number; + /** + * Position in block (filter: gte) + */ + transaction_index_gte?: number; + /** + * Position in block (filter: between_min) + */ + transaction_index_between_min?: number; + /** + * Position in block (filter: between_max_value) + */ + transaction_index_between_max_value?: number; + /** + * Position in block (filter: in_values) (comma-separated list) + */ + transaction_index_in_values?: string; + /** + * Position in block (filter: not_in_values) (comma-separated list) + */ + transaction_index_not_in_values?: string; + /** + * Position within transaction traces (filter: eq) + */ + internal_index_eq?: number; + /** + * Position within transaction traces (filter: ne) + */ + internal_index_ne?: number; + /** + * Position within transaction traces (filter: lt) + */ + internal_index_lt?: number; + /** + * Position within transaction traces (filter: lte) + */ + internal_index_lte?: number; + /** + * Position within transaction traces (filter: gt) + */ + internal_index_gt?: number; + /** + * Position within transaction traces (filter: gte) + */ + internal_index_gte?: number; + /** + * Position within transaction traces (filter: between_min) + */ + internal_index_between_min?: number; + /** + * Position within transaction traces (filter: between_max_value) + */ + internal_index_between_max_value?: number; + /** + * Position within transaction traces (filter: in_values) (comma-separated list) + */ + internal_index_in_values?: string; + /** + * Position within transaction traces (filter: not_in_values) (comma-separated list) + */ + internal_index_not_in_values?: string; + /** + * Contract that was destroyed (filter: eq) + */ + address_eq?: string; + /** + * Contract that was destroyed (filter: ne) + */ + address_ne?: string; + /** + * Contract that was destroyed (filter: contains) + */ + address_contains?: string; + /** + * Contract that was destroyed (filter: starts_with) + */ + address_starts_with?: string; + /** + * Contract that was destroyed (filter: ends_with) + */ + address_ends_with?: string; + /** + * Contract that was destroyed (filter: like) + */ + address_like?: string; + /** + * Contract that was destroyed (filter: not_like) + */ + address_not_like?: string; + /** + * Contract that was destroyed (filter: in_values) (comma-separated list) + */ + address_in_values?: string; + /** + * Contract that was destroyed (filter: not_in_values) (comma-separated list) + */ + address_not_in_values?: string; + /** + * Timestamp when the record was last updated (filter: eq) + */ + updated_date_time_eq?: number; + /** + * Timestamp when the record was last updated (filter: ne) + */ + updated_date_time_ne?: number; + /** + * Timestamp when the record was last updated (filter: lt) + */ + updated_date_time_lt?: number; + /** + * Timestamp when the record was last updated (filter: lte) + */ + updated_date_time_lte?: number; + /** + * Timestamp when the record was last updated (filter: gt) + */ + updated_date_time_gt?: number; + /** + * Timestamp when the record was last updated (filter: gte) + */ + updated_date_time_gte?: number; + /** + * Timestamp when the record was last updated (filter: between_min) + */ + updated_date_time_between_min?: number; + /** + * Timestamp when the record was last updated (filter: between_max_value) + */ + updated_date_time_between_max_value?: number; + /** + * Timestamp when the record was last updated (filter: in_values) (comma-separated list) + */ + updated_date_time_in_values?: string; + /** + * Timestamp when the record was last updated (filter: not_in_values) (comma-separated list) + */ + updated_date_time_not_in_values?: string; + /** + * Transaction hash (filter: eq) + */ + transaction_hash_eq?: string; + /** + * Transaction hash (filter: ne) + */ + transaction_hash_ne?: string; + /** + * Transaction hash (filter: contains) + */ + transaction_hash_contains?: string; + /** + * Transaction hash (filter: starts_with) + */ + transaction_hash_starts_with?: string; + /** + * Transaction hash (filter: ends_with) + */ + transaction_hash_ends_with?: string; + /** + * Transaction hash (filter: like) + */ + transaction_hash_like?: string; + /** + * Transaction hash (filter: not_like) + */ + transaction_hash_not_like?: string; + /** + * Transaction hash (filter: in_values) (comma-separated list) + */ + transaction_hash_in_values?: string; + /** + * Transaction hash (filter: not_in_values) (comma-separated list) + */ + transaction_hash_not_in_values?: string; + /** + * Address receiving the ETH (filter: eq) + */ + beneficiary_eq?: string; + /** + * Address receiving the ETH (filter: ne) + */ + beneficiary_ne?: string; + /** + * Address receiving the ETH (filter: contains) + */ + beneficiary_contains?: string; + /** + * Address receiving the ETH (filter: starts_with) + */ + beneficiary_starts_with?: string; + /** + * Address receiving the ETH (filter: ends_with) + */ + beneficiary_ends_with?: string; + /** + * Address receiving the ETH (filter: like) + */ + beneficiary_like?: string; + /** + * Address receiving the ETH (filter: not_like) + */ + beneficiary_not_like?: string; + /** + * Address receiving the ETH (filter: in_values) (comma-separated list) + */ + beneficiary_in_values?: string; + /** + * Address receiving the ETH (filter: not_in_values) (comma-separated list) + */ + beneficiary_not_in_values?: string; + /** + * Amount of ETH sent to beneficiary (filter: eq) + */ + value_transferred_eq?: string; + /** + * Amount of ETH sent to beneficiary (filter: ne) + */ + value_transferred_ne?: string; + /** + * Amount of ETH sent to beneficiary (filter: contains) + */ + value_transferred_contains?: string; + /** + * Amount of ETH sent to beneficiary (filter: starts_with) + */ + value_transferred_starts_with?: string; + /** + * Amount of ETH sent to beneficiary (filter: ends_with) + */ + value_transferred_ends_with?: string; + /** + * Amount of ETH sent to beneficiary (filter: like) + */ + value_transferred_like?: string; + /** + * Amount of ETH sent to beneficiary (filter: not_like) + */ + value_transferred_not_like?: string; + /** + * Amount of ETH sent to beneficiary (filter: in_values) (comma-separated list) + */ + value_transferred_in_values?: string; + /** + * Amount of ETH sent to beneficiary (filter: not_in_values) (comma-separated list) + */ + value_transferred_not_in_values?: string; + /** + * True if contract was created and destroyed in the same transaction - storage always cleared per EIP-6780 (filter: eq) + */ + ephemeral_eq?: boolean; + /** + * True if contract was created and destroyed in the same transaction - storage always cleared per EIP-6780 (filter: ne) + */ + ephemeral_ne?: boolean; + /** + * True if storage was cleared (pre-Shanghai OR ephemeral) (filter: eq) + */ + storage_cleared_eq?: boolean; + /** + * True if storage was cleared (pre-Shanghai OR ephemeral) (filter: ne) + */ + storage_cleared_ne?: boolean; + /** + * Block where contract was created (if known) (filter: eq) + */ + creation_block_eq?: number; + /** + * Block where contract was created (if known) (filter: ne) + */ + creation_block_ne?: number; + /** + * Block where contract was created (if known) (filter: lt) + */ + creation_block_lt?: number; + /** + * Block where contract was created (if known) (filter: lte) + */ + creation_block_lte?: number; + /** + * Block where contract was created (if known) (filter: gt) + */ + creation_block_gt?: number; + /** + * Block where contract was created (if known) (filter: gte) + */ + creation_block_gte?: number; + /** + * Block where contract was created (if known) (filter: between_min) + */ + creation_block_between_min?: number; + /** + * Block where contract was created (if known) (filter: between_max_value) + */ + creation_block_between_max_value?: number; + /** + * Block where contract was created (if known) (filter: in_values) (comma-separated list) + */ + creation_block_in_values?: string; + /** + * Block where contract was created (if known) (filter: not_in_values) (comma-separated list) + */ + creation_block_not_in_values?: string; + /** + * Transaction that created the contract (if known) (filter: eq) + */ + creation_transaction_hash_eq?: string; + /** + * Transaction that created the contract (if known) (filter: ne) + */ + creation_transaction_hash_ne?: string; + /** + * Transaction that created the contract (if known) (filter: contains) + */ + creation_transaction_hash_contains?: string; + /** + * Transaction that created the contract (if known) (filter: starts_with) + */ + creation_transaction_hash_starts_with?: string; + /** + * Transaction that created the contract (if known) (filter: ends_with) + */ + creation_transaction_hash_ends_with?: string; + /** + * Transaction that created the contract (if known) (filter: like) + */ + creation_transaction_hash_like?: string; + /** + * Transaction that created the contract (if known) (filter: not_like) + */ + creation_transaction_hash_not_like?: string; + /** + * Transaction that created the contract (if known) (filter: in_values) (comma-separated list) + */ + creation_transaction_hash_in_values?: string; + /** + * Transaction that created the contract (if known) (filter: not_in_values) (comma-separated list) + */ + creation_transaction_hash_not_in_values?: string; + /** + * The maximum number of int_contract_selfdestruct to return. If unspecified, at most 100 items will be returned. The maximum value is 10000; values above 10000 will be coerced to 10000. + */ + page_size?: number; + /** + * A page token, received from a previous `ListIntContractSelfdestruct` call. Provide this to retrieve the subsequent page. + */ + page_token?: string; + /** + * The order of results. Format: comma-separated list of fields. Example: "foo,bar" or "foo desc,bar" for descending order on foo. If unspecified, results will be returned in the default order. + */ + order_by?: string; + }; + url: '/api/v1/int_contract_selfdestruct'; +}; + +export type IntContractSelfdestructServiceListErrors = { + /** + * Default error response + */ + default: Status; +}; + +export type IntContractSelfdestructServiceListError = + IntContractSelfdestructServiceListErrors[keyof IntContractSelfdestructServiceListErrors]; + +export type IntContractSelfdestructServiceListResponses = { + /** + * OK + */ + 200: ListIntContractSelfdestructResponse; +}; + +export type IntContractSelfdestructServiceListResponse = + IntContractSelfdestructServiceListResponses[keyof IntContractSelfdestructServiceListResponses]; + +export type IntContractSelfdestructServiceGetData = { + body?: never; + path: { + /** + * Block where SELFDESTRUCT occurred + */ + block_number: number; + }; + query?: never; + url: '/api/v1/int_contract_selfdestruct/{block_number}'; +}; + +export type IntContractSelfdestructServiceGetErrors = { + /** + * Default error response + */ + default: Status; +}; + +export type IntContractSelfdestructServiceGetError = + IntContractSelfdestructServiceGetErrors[keyof IntContractSelfdestructServiceGetErrors]; + +export type IntContractSelfdestructServiceGetResponses = { + /** + * OK + */ + 200: GetIntContractSelfdestructResponse; +}; + +export type IntContractSelfdestructServiceGetResponse = + IntContractSelfdestructServiceGetResponses[keyof IntContractSelfdestructServiceGetResponses]; + export type IntContractStorageExpiry1mServiceListData = { body?: never; path?: never; @@ -80445,7 +82069,7 @@ export type IntEngineNewPayloadServiceGetResponses = { export type IntEngineNewPayloadServiceGetResponse = IntEngineNewPayloadServiceGetResponses[keyof IntEngineNewPayloadServiceGetResponses]; -export type IntEngineNewPayloadFastestServiceListData = { +export type IntEngineNewPayloadFastestExecutionByNodeClassServiceListData = { body?: never; path?: never; query?: { @@ -80870,11 +82494,11 @@ export type IntEngineNewPayloadFastestServiceListData = { */ meta_client_name_not_in_values?: string; /** - * The maximum number of int_engine_new_payload_fastest to return. If unspecified, at most 100 items will be returned. The maximum value is 10000; values above 10000 will be coerced to 10000. + * The maximum number of int_engine_new_payload_fastest_execution_by_node_class to return. If unspecified, at most 100 items will be returned. The maximum value is 10000; values above 10000 will be coerced to 10000. */ page_size?: number; /** - * A page token, received from a previous `ListIntEngineNewPayloadFastest` call. Provide this to retrieve the subsequent page. + * A page token, received from a previous `ListIntEngineNewPayloadFastestExecutionByNodeClass` call. Provide this to retrieve the subsequent page. */ page_token?: string; /** @@ -80882,30 +82506,30 @@ export type IntEngineNewPayloadFastestServiceListData = { */ order_by?: string; }; - url: '/api/v1/int_engine_new_payload_fastest'; + url: '/api/v1/int_engine_new_payload_fastest_execution_by_node_class'; }; -export type IntEngineNewPayloadFastestServiceListErrors = { +export type IntEngineNewPayloadFastestExecutionByNodeClassServiceListErrors = { /** * Default error response */ default: Status; }; -export type IntEngineNewPayloadFastestServiceListError = - IntEngineNewPayloadFastestServiceListErrors[keyof IntEngineNewPayloadFastestServiceListErrors]; +export type IntEngineNewPayloadFastestExecutionByNodeClassServiceListError = + IntEngineNewPayloadFastestExecutionByNodeClassServiceListErrors[keyof IntEngineNewPayloadFastestExecutionByNodeClassServiceListErrors]; -export type IntEngineNewPayloadFastestServiceListResponses = { +export type IntEngineNewPayloadFastestExecutionByNodeClassServiceListResponses = { /** * OK */ - 200: ListIntEngineNewPayloadFastestResponse; + 200: ListIntEngineNewPayloadFastestExecutionByNodeClassResponse; }; -export type IntEngineNewPayloadFastestServiceListResponse = - IntEngineNewPayloadFastestServiceListResponses[keyof IntEngineNewPayloadFastestServiceListResponses]; +export type IntEngineNewPayloadFastestExecutionByNodeClassServiceListResponse = + IntEngineNewPayloadFastestExecutionByNodeClassServiceListResponses[keyof IntEngineNewPayloadFastestExecutionByNodeClassServiceListResponses]; -export type IntEngineNewPayloadFastestServiceGetData = { +export type IntEngineNewPayloadFastestExecutionByNodeClassServiceGetData = { body?: never; path: { /** @@ -80914,28 +82538,28 @@ export type IntEngineNewPayloadFastestServiceGetData = { slot_start_date_time: number; }; query?: never; - url: '/api/v1/int_engine_new_payload_fastest/{slot_start_date_time}'; + url: '/api/v1/int_engine_new_payload_fastest_execution_by_node_class/{slot_start_date_time}'; }; -export type IntEngineNewPayloadFastestServiceGetErrors = { +export type IntEngineNewPayloadFastestExecutionByNodeClassServiceGetErrors = { /** * Default error response */ default: Status; }; -export type IntEngineNewPayloadFastestServiceGetError = - IntEngineNewPayloadFastestServiceGetErrors[keyof IntEngineNewPayloadFastestServiceGetErrors]; +export type IntEngineNewPayloadFastestExecutionByNodeClassServiceGetError = + IntEngineNewPayloadFastestExecutionByNodeClassServiceGetErrors[keyof IntEngineNewPayloadFastestExecutionByNodeClassServiceGetErrors]; -export type IntEngineNewPayloadFastestServiceGetResponses = { +export type IntEngineNewPayloadFastestExecutionByNodeClassServiceGetResponses = { /** * OK */ - 200: GetIntEngineNewPayloadFastestResponse; + 200: GetIntEngineNewPayloadFastestExecutionByNodeClassResponse; }; -export type IntEngineNewPayloadFastestServiceGetResponse = - IntEngineNewPayloadFastestServiceGetResponses[keyof IntEngineNewPayloadFastestServiceGetResponses]; +export type IntEngineNewPayloadFastestExecutionByNodeClassServiceGetResponse = + IntEngineNewPayloadFastestExecutionByNodeClassServiceGetResponses[keyof IntEngineNewPayloadFastestExecutionByNodeClassServiceGetResponses]; export type IntExecutionBlockByDateServiceListData = { body?: never; @@ -81129,6 +82753,418 @@ export type IntExecutionBlockByDateServiceGetResponses = { export type IntExecutionBlockByDateServiceGetResponse = IntExecutionBlockByDateServiceGetResponses[keyof IntExecutionBlockByDateServiceGetResponses]; +export type IntStorageSelfdestructDiffsServiceListData = { + body?: never; + path?: never; + query?: { + /** + * Block where SELFDESTRUCT occurred (filter: eq) + */ + block_number_eq?: number; + /** + * Block where SELFDESTRUCT occurred (filter: ne) + */ + block_number_ne?: number; + /** + * Block where SELFDESTRUCT occurred (filter: lt) + */ + block_number_lt?: number; + /** + * Block where SELFDESTRUCT occurred (filter: lte) + */ + block_number_lte?: number; + /** + * Block where SELFDESTRUCT occurred (filter: gt) + */ + block_number_gt?: number; + /** + * Block where SELFDESTRUCT occurred (filter: gte) + */ + block_number_gte?: number; + /** + * Block where SELFDESTRUCT occurred (filter: between_min) + */ + block_number_between_min?: number; + /** + * Block where SELFDESTRUCT occurred (filter: between_max_value) + */ + block_number_between_max_value?: number; + /** + * Block where SELFDESTRUCT occurred (filter: in_values) (comma-separated list) + */ + block_number_in_values?: string; + /** + * Block where SELFDESTRUCT occurred (filter: not_in_values) (comma-separated list) + */ + block_number_not_in_values?: string; + /** + * Transaction hash of the SELFDESTRUCT (filter: eq) + */ + transaction_hash_eq?: string; + /** + * Transaction hash of the SELFDESTRUCT (filter: ne) + */ + transaction_hash_ne?: string; + /** + * Transaction hash of the SELFDESTRUCT (filter: contains) + */ + transaction_hash_contains?: string; + /** + * Transaction hash of the SELFDESTRUCT (filter: starts_with) + */ + transaction_hash_starts_with?: string; + /** + * Transaction hash of the SELFDESTRUCT (filter: ends_with) + */ + transaction_hash_ends_with?: string; + /** + * Transaction hash of the SELFDESTRUCT (filter: like) + */ + transaction_hash_like?: string; + /** + * Transaction hash of the SELFDESTRUCT (filter: not_like) + */ + transaction_hash_not_like?: string; + /** + * Transaction hash of the SELFDESTRUCT (filter: in_values) (comma-separated list) + */ + transaction_hash_in_values?: string; + /** + * Transaction hash of the SELFDESTRUCT (filter: not_in_values) (comma-separated list) + */ + transaction_hash_not_in_values?: string; + /** + * Internal index of the SELFDESTRUCT trace (filter: eq) + */ + internal_index_eq?: number; + /** + * Internal index of the SELFDESTRUCT trace (filter: ne) + */ + internal_index_ne?: number; + /** + * Internal index of the SELFDESTRUCT trace (filter: lt) + */ + internal_index_lt?: number; + /** + * Internal index of the SELFDESTRUCT trace (filter: lte) + */ + internal_index_lte?: number; + /** + * Internal index of the SELFDESTRUCT trace (filter: gt) + */ + internal_index_gt?: number; + /** + * Internal index of the SELFDESTRUCT trace (filter: gte) + */ + internal_index_gte?: number; + /** + * Internal index of the SELFDESTRUCT trace (filter: between_min) + */ + internal_index_between_min?: number; + /** + * Internal index of the SELFDESTRUCT trace (filter: between_max_value) + */ + internal_index_between_max_value?: number; + /** + * Internal index of the SELFDESTRUCT trace (filter: in_values) (comma-separated list) + */ + internal_index_in_values?: string; + /** + * Internal index of the SELFDESTRUCT trace (filter: not_in_values) (comma-separated list) + */ + internal_index_not_in_values?: string; + /** + * Storage slot key being cleared (filter: eq) + */ + slot_eq?: string; + /** + * Storage slot key being cleared (filter: ne) + */ + slot_ne?: string; + /** + * Storage slot key being cleared (filter: contains) + */ + slot_contains?: string; + /** + * Storage slot key being cleared (filter: starts_with) + */ + slot_starts_with?: string; + /** + * Storage slot key being cleared (filter: ends_with) + */ + slot_ends_with?: string; + /** + * Storage slot key being cleared (filter: like) + */ + slot_like?: string; + /** + * Storage slot key being cleared (filter: not_like) + */ + slot_not_like?: string; + /** + * Storage slot key being cleared (filter: in_values) (comma-separated list) + */ + slot_in_values?: string; + /** + * Storage slot key being cleared (filter: not_in_values) (comma-separated list) + */ + slot_not_in_values?: string; + /** + * Timestamp when the record was last updated (filter: eq) + */ + updated_date_time_eq?: number; + /** + * Timestamp when the record was last updated (filter: ne) + */ + updated_date_time_ne?: number; + /** + * Timestamp when the record was last updated (filter: lt) + */ + updated_date_time_lt?: number; + /** + * Timestamp when the record was last updated (filter: lte) + */ + updated_date_time_lte?: number; + /** + * Timestamp when the record was last updated (filter: gt) + */ + updated_date_time_gt?: number; + /** + * Timestamp when the record was last updated (filter: gte) + */ + updated_date_time_gte?: number; + /** + * Timestamp when the record was last updated (filter: between_min) + */ + updated_date_time_between_min?: number; + /** + * Timestamp when the record was last updated (filter: between_max_value) + */ + updated_date_time_between_max_value?: number; + /** + * Timestamp when the record was last updated (filter: in_values) (comma-separated list) + */ + updated_date_time_in_values?: string; + /** + * Timestamp when the record was last updated (filter: not_in_values) (comma-separated list) + */ + updated_date_time_not_in_values?: string; + /** + * Transaction index within the block (filter: eq) + */ + transaction_index_eq?: number; + /** + * Transaction index within the block (filter: ne) + */ + transaction_index_ne?: number; + /** + * Transaction index within the block (filter: lt) + */ + transaction_index_lt?: number; + /** + * Transaction index within the block (filter: lte) + */ + transaction_index_lte?: number; + /** + * Transaction index within the block (filter: gt) + */ + transaction_index_gt?: number; + /** + * Transaction index within the block (filter: gte) + */ + transaction_index_gte?: number; + /** + * Transaction index within the block (filter: between_min) + */ + transaction_index_between_min?: number; + /** + * Transaction index within the block (filter: between_max_value) + */ + transaction_index_between_max_value?: number; + /** + * Transaction index within the block (filter: in_values) (comma-separated list) + */ + transaction_index_in_values?: string; + /** + * Transaction index within the block (filter: not_in_values) (comma-separated list) + */ + transaction_index_not_in_values?: string; + /** + * Contract address that was selfdestructed (filter: eq) + */ + address_eq?: string; + /** + * Contract address that was selfdestructed (filter: ne) + */ + address_ne?: string; + /** + * Contract address that was selfdestructed (filter: contains) + */ + address_contains?: string; + /** + * Contract address that was selfdestructed (filter: starts_with) + */ + address_starts_with?: string; + /** + * Contract address that was selfdestructed (filter: ends_with) + */ + address_ends_with?: string; + /** + * Contract address that was selfdestructed (filter: like) + */ + address_like?: string; + /** + * Contract address that was selfdestructed (filter: not_like) + */ + address_not_like?: string; + /** + * Contract address that was selfdestructed (filter: in_values) (comma-separated list) + */ + address_in_values?: string; + /** + * Contract address that was selfdestructed (filter: not_in_values) (comma-separated list) + */ + address_not_in_values?: string; + /** + * Value before clearing (last known value) (filter: eq) + */ + from_value_eq?: string; + /** + * Value before clearing (last known value) (filter: ne) + */ + from_value_ne?: string; + /** + * Value before clearing (last known value) (filter: contains) + */ + from_value_contains?: string; + /** + * Value before clearing (last known value) (filter: starts_with) + */ + from_value_starts_with?: string; + /** + * Value before clearing (last known value) (filter: ends_with) + */ + from_value_ends_with?: string; + /** + * Value before clearing (last known value) (filter: like) + */ + from_value_like?: string; + /** + * Value before clearing (last known value) (filter: not_like) + */ + from_value_not_like?: string; + /** + * Value before clearing (last known value) (filter: in_values) (comma-separated list) + */ + from_value_in_values?: string; + /** + * Value before clearing (last known value) (filter: not_in_values) (comma-separated list) + */ + from_value_not_in_values?: string; + /** + * Value after clearing (always 0x00...00) (filter: eq) + */ + to_value_eq?: string; + /** + * Value after clearing (always 0x00...00) (filter: ne) + */ + to_value_ne?: string; + /** + * Value after clearing (always 0x00...00) (filter: contains) + */ + to_value_contains?: string; + /** + * Value after clearing (always 0x00...00) (filter: starts_with) + */ + to_value_starts_with?: string; + /** + * Value after clearing (always 0x00...00) (filter: ends_with) + */ + to_value_ends_with?: string; + /** + * Value after clearing (always 0x00...00) (filter: like) + */ + to_value_like?: string; + /** + * Value after clearing (always 0x00...00) (filter: not_like) + */ + to_value_not_like?: string; + /** + * Value after clearing (always 0x00...00) (filter: in_values) (comma-separated list) + */ + to_value_in_values?: string; + /** + * Value after clearing (always 0x00...00) (filter: not_in_values) (comma-separated list) + */ + to_value_not_in_values?: string; + /** + * The maximum number of int_storage_selfdestruct_diffs to return. If unspecified, at most 100 items will be returned. The maximum value is 10000; values above 10000 will be coerced to 10000. + */ + page_size?: number; + /** + * A page token, received from a previous `ListIntStorageSelfdestructDiffs` call. Provide this to retrieve the subsequent page. + */ + page_token?: string; + /** + * The order of results. Format: comma-separated list of fields. Example: "foo,bar" or "foo desc,bar" for descending order on foo. If unspecified, results will be returned in the default order. + */ + order_by?: string; + }; + url: '/api/v1/int_storage_selfdestruct_diffs'; +}; + +export type IntStorageSelfdestructDiffsServiceListErrors = { + /** + * Default error response + */ + default: Status; +}; + +export type IntStorageSelfdestructDiffsServiceListError = + IntStorageSelfdestructDiffsServiceListErrors[keyof IntStorageSelfdestructDiffsServiceListErrors]; + +export type IntStorageSelfdestructDiffsServiceListResponses = { + /** + * OK + */ + 200: ListIntStorageSelfdestructDiffsResponse; +}; + +export type IntStorageSelfdestructDiffsServiceListResponse = + IntStorageSelfdestructDiffsServiceListResponses[keyof IntStorageSelfdestructDiffsServiceListResponses]; + +export type IntStorageSelfdestructDiffsServiceGetData = { + body?: never; + path: { + /** + * Block where SELFDESTRUCT occurred + */ + block_number: number; + }; + query?: never; + url: '/api/v1/int_storage_selfdestruct_diffs/{block_number}'; +}; + +export type IntStorageSelfdestructDiffsServiceGetErrors = { + /** + * Default error response + */ + default: Status; +}; + +export type IntStorageSelfdestructDiffsServiceGetError = + IntStorageSelfdestructDiffsServiceGetErrors[keyof IntStorageSelfdestructDiffsServiceGetErrors]; + +export type IntStorageSelfdestructDiffsServiceGetResponses = { + /** + * OK + */ + 200: GetIntStorageSelfdestructDiffsResponse; +}; + +export type IntStorageSelfdestructDiffsServiceGetResponse = + IntStorageSelfdestructDiffsServiceGetResponses[keyof IntStorageSelfdestructDiffsServiceGetResponses]; + export type IntStorageSlotDiffServiceListData = { body?: never; path?: never; diff --git a/src/api/zod.gen.ts b/src/api/zod.gen.ts index 44cd58548..8629aa971 100644 --- a/src/api/zod.gen.ts +++ b/src/api/zod.gen.ts @@ -6631,6 +6631,73 @@ export const zFctNodeActiveLast24h = z.object({ username: z.optional(z.string()), }); +export const zFctNodeCpuUtilization = z.object({ + client_type: z.optional(z.string()), + max_core_pct: z.optional(z.number()), + max_single_core_pct: z.optional(z.number()), + mean_core_pct: z.optional(z.number()), + meta_client_name: z.optional(z.string()), + meta_network_name: z.optional(z.string()), + min_core_pct: z.optional(z.number()), + node_class: z.optional(z.string()), + pid: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + system_cores: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_start_date_time: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), +}); + export const zFctOpcodeGasByOpcodeDaily = z.object({ avg_count_per_block: z.optional(z.number()), avg_gas_per_block: z.optional(z.number()), @@ -8582,6 +8649,13 @@ export const zGetFctNodeActiveLast24hResponse = z.object({ item: z.optional(zFctNodeActiveLast24h), }); +/** + * Response for getting a single fct_node_cpu_utilization record + */ +export const zGetFctNodeCpuUtilizationResponse = z.object({ + item: z.optional(zFctNodeCpuUtilization), +}); + /** * Response for getting a single fct_opcode_gas_by_opcode_daily record */ @@ -9692,18 +9766,7 @@ export const zGetIntBlockProposerCanonicalResponse = z.object({ item: z.optional(zIntBlockProposerCanonical), }); -export const zIntContractStorageExpiry1m = z.object({ - active_slots: z.optional( - z.coerce - .bigint() - .check( - z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), - z.maximum(BigInt('18446744073709551615'), { - error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', - }) - ) - ), - address: z.optional(z.string()), +export const zIntContractCreation = z.object({ block_number: z.optional( z .int() @@ -9712,17 +9775,20 @@ export const zIntContractStorageExpiry1m = z.object({ z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) ) ), - effective_bytes: z.optional( - z.coerce - .bigint() + contract_address: z.optional(z.string()), + deployer: z.optional(z.string()), + factory: z.optional(z.string()), + init_code_hash: z.optional(z.string()), + internal_index: z.optional( + z + .int() .check( - z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), - z.maximum(BigInt('18446744073709551615'), { - error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', - }) + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) ) ), - touch_block: z.optional( + transaction_hash: z.optional(z.string()), + transaction_index: z.optional( z .int() .check( @@ -9741,24 +9807,15 @@ export const zIntContractStorageExpiry1m = z.object({ }); /** - * Response for getting a single int_contract_storage_expiry_1m record + * Response for getting a single int_contract_creation record */ -export const zGetIntContractStorageExpiry1mResponse = z.object({ - item: z.optional(zIntContractStorageExpiry1m), +export const zGetIntContractCreationResponse = z.object({ + item: z.optional(zIntContractCreation), }); -export const zIntContractStorageExpiry6m = z.object({ - active_slots: z.optional( - z.coerce - .bigint() - .check( - z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), - z.maximum(BigInt('18446744073709551615'), { - error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', - }) - ) - ), +export const zIntContractSelfdestruct = z.object({ address: z.optional(z.string()), + beneficiary: z.optional(z.string()), block_number: z.optional( z .int() @@ -9767,17 +9824,30 @@ export const zIntContractStorageExpiry6m = z.object({ z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) ) ), - effective_bytes: z.optional( - z.coerce - .bigint() + creation_block: z.optional( + z.union([ + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ), + z.null(), + ]) + ), + creation_transaction_hash: z.optional(z.union([z.string(), z.null()])), + ephemeral: z.optional(z.boolean()), + internal_index: z.optional( + z + .int() .check( - z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), - z.maximum(BigInt('18446744073709551615'), { - error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', - }) + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) ) ), - touch_block: z.optional( + storage_cleared: z.optional(z.boolean()), + transaction_hash: z.optional(z.string()), + transaction_index: z.optional( z .int() .check( @@ -9793,16 +9863,17 @@ export const zIntContractStorageExpiry6m = z.object({ z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) ) ), + value_transferred: z.optional(z.string()), }); /** - * Response for getting a single int_contract_storage_expiry_6m record + * Response for getting a single int_contract_selfdestruct record */ -export const zGetIntContractStorageExpiry6mResponse = z.object({ - item: z.optional(zIntContractStorageExpiry6m), +export const zGetIntContractSelfdestructResponse = z.object({ + item: z.optional(zIntContractSelfdestruct), }); -export const zIntContractStorageExpiry12m = z.object({ +export const zIntContractStorageExpiry1m = z.object({ active_slots: z.optional( z.coerce .bigint() @@ -9851,13 +9922,13 @@ export const zIntContractStorageExpiry12m = z.object({ }); /** - * Response for getting a single int_contract_storage_expiry_12m record + * Response for getting a single int_contract_storage_expiry_1m record */ -export const zGetIntContractStorageExpiry12mResponse = z.object({ - item: z.optional(zIntContractStorageExpiry12m), +export const zGetIntContractStorageExpiry1mResponse = z.object({ + item: z.optional(zIntContractStorageExpiry1m), }); -export const zIntContractStorageExpiry18m = z.object({ +export const zIntContractStorageExpiry6m = z.object({ active_slots: z.optional( z.coerce .bigint() @@ -9906,13 +9977,13 @@ export const zIntContractStorageExpiry18m = z.object({ }); /** - * Response for getting a single int_contract_storage_expiry_18m record + * Response for getting a single int_contract_storage_expiry_6m record */ -export const zGetIntContractStorageExpiry18mResponse = z.object({ - item: z.optional(zIntContractStorageExpiry18m), +export const zGetIntContractStorageExpiry6mResponse = z.object({ + item: z.optional(zIntContractStorageExpiry6m), }); -export const zIntContractStorageExpiry24m = z.object({ +export const zIntContractStorageExpiry12m = z.object({ active_slots: z.optional( z.coerce .bigint() @@ -9961,51 +10032,13 @@ export const zIntContractStorageExpiry24m = z.object({ }); /** - * Response for getting a single int_contract_storage_expiry_24m record - */ -export const zGetIntContractStorageExpiry24mResponse = z.object({ - item: z.optional(zIntContractStorageExpiry24m), -}); - -export const zIntContractStorageNextTouch = z.object({ - address: z.optional(z.string()), - block_number: z.optional( - z - .int() - .check( - z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), - z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) - ) - ), - next_touch_block: z.optional( - z.union([ - z - .int() - .check( - z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), - z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) - ), - z.null(), - ]) - ), - updated_date_time: z.optional( - z - .int() - .check( - z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), - z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) - ) - ), -}); - -/** - * Response for getting a single int_contract_storage_next_touch record + * Response for getting a single int_contract_storage_expiry_12m record */ -export const zGetIntContractStorageNextTouchResponse = z.object({ - item: z.optional(zIntContractStorageNextTouch), +export const zGetIntContractStorageExpiry12mResponse = z.object({ + item: z.optional(zIntContractStorageExpiry12m), }); -export const zIntContractStorageReactivation1m = z.object({ +export const zIntContractStorageExpiry18m = z.object({ active_slots: z.optional( z.coerce .bigint() @@ -10054,13 +10087,13 @@ export const zIntContractStorageReactivation1m = z.object({ }); /** - * Response for getting a single int_contract_storage_reactivation_1m record + * Response for getting a single int_contract_storage_expiry_18m record */ -export const zGetIntContractStorageReactivation1mResponse = z.object({ - item: z.optional(zIntContractStorageReactivation1m), +export const zGetIntContractStorageExpiry18mResponse = z.object({ + item: z.optional(zIntContractStorageExpiry18m), }); -export const zIntContractStorageReactivation6m = z.object({ +export const zIntContractStorageExpiry24m = z.object({ active_slots: z.optional( z.coerce .bigint() @@ -10109,23 +10142,13 @@ export const zIntContractStorageReactivation6m = z.object({ }); /** - * Response for getting a single int_contract_storage_reactivation_6m record + * Response for getting a single int_contract_storage_expiry_24m record */ -export const zGetIntContractStorageReactivation6mResponse = z.object({ - item: z.optional(zIntContractStorageReactivation6m), +export const zGetIntContractStorageExpiry24mResponse = z.object({ + item: z.optional(zIntContractStorageExpiry24m), }); -export const zIntContractStorageReactivation12m = z.object({ - active_slots: z.optional( - z.coerce - .bigint() - .check( - z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), - z.maximum(BigInt('18446744073709551615'), { - error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', - }) - ) - ), +export const zIntContractStorageNextTouch = z.object({ address: z.optional(z.string()), block_number: z.optional( z @@ -10135,23 +10158,16 @@ export const zIntContractStorageReactivation12m = z.object({ z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) ) ), - effective_bytes: z.optional( - z.coerce - .bigint() - .check( - z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), - z.maximum(BigInt('18446744073709551615'), { - error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', - }) - ) - ), - touch_block: z.optional( - z - .int() - .check( - z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), - z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) - ) + next_touch_block: z.optional( + z.union([ + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ), + z.null(), + ]) ), updated_date_time: z.optional( z @@ -10164,13 +10180,13 @@ export const zIntContractStorageReactivation12m = z.object({ }); /** - * Response for getting a single int_contract_storage_reactivation_12m record + * Response for getting a single int_contract_storage_next_touch record */ -export const zGetIntContractStorageReactivation12mResponse = z.object({ - item: z.optional(zIntContractStorageReactivation12m), +export const zGetIntContractStorageNextTouchResponse = z.object({ + item: z.optional(zIntContractStorageNextTouch), }); -export const zIntContractStorageReactivation18m = z.object({ +export const zIntContractStorageReactivation1m = z.object({ active_slots: z.optional( z.coerce .bigint() @@ -10219,13 +10235,178 @@ export const zIntContractStorageReactivation18m = z.object({ }); /** - * Response for getting a single int_contract_storage_reactivation_18m record + * Response for getting a single int_contract_storage_reactivation_1m record */ -export const zGetIntContractStorageReactivation18mResponse = z.object({ - item: z.optional(zIntContractStorageReactivation18m), +export const zGetIntContractStorageReactivation1mResponse = z.object({ + item: z.optional(zIntContractStorageReactivation1m), }); -export const zIntContractStorageReactivation24m = z.object({ +export const zIntContractStorageReactivation6m = z.object({ + active_slots: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + address: z.optional(z.string()), + block_number: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + effective_bytes: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + touch_block: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), +}); + +/** + * Response for getting a single int_contract_storage_reactivation_6m record + */ +export const zGetIntContractStorageReactivation6mResponse = z.object({ + item: z.optional(zIntContractStorageReactivation6m), +}); + +export const zIntContractStorageReactivation12m = z.object({ + active_slots: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + address: z.optional(z.string()), + block_number: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + effective_bytes: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + touch_block: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), +}); + +/** + * Response for getting a single int_contract_storage_reactivation_12m record + */ +export const zGetIntContractStorageReactivation12mResponse = z.object({ + item: z.optional(zIntContractStorageReactivation12m), +}); + +export const zIntContractStorageReactivation18m = z.object({ + active_slots: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + address: z.optional(z.string()), + block_number: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + effective_bytes: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + touch_block: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), +}); + +/** + * Response for getting a single int_contract_storage_reactivation_18m record + */ +export const zGetIntContractStorageReactivation18mResponse = z.object({ + item: z.optional(zIntContractStorageReactivation18m), +}); + +export const zIntContractStorageReactivation24m = z.object({ active_slots: z.optional( z.coerce .bigint() @@ -11331,7 +11512,7 @@ export const zGetIntEngineNewPayloadResponse = z.object({ item: z.optional(zIntEngineNewPayload), }); -export const zIntEngineNewPayloadFastest = z.object({ +export const zIntEngineNewPayloadFastestExecutionByNodeClass = z.object({ block_hash: z.optional(z.string()), duration_ms: z.optional( z.coerce @@ -11390,10 +11571,10 @@ export const zIntEngineNewPayloadFastest = z.object({ }); /** - * Response for getting a single int_engine_new_payload_fastest record + * Response for getting a single int_engine_new_payload_fastest_execution_by_node_class record */ -export const zGetIntEngineNewPayloadFastestResponse = z.object({ - item: z.optional(zIntEngineNewPayloadFastest), +export const zGetIntEngineNewPayloadFastestExecutionByNodeClassResponse = z.object({ + item: z.optional(zIntEngineNewPayloadFastestExecutionByNodeClass), }); export const zIntExecutionBlockByDate = z.object({ @@ -11436,7 +11617,7 @@ export const zGetIntExecutionBlockByDateResponse = z.object({ item: z.optional(zIntExecutionBlockByDate), }); -export const zIntStorageSlotDiff = z.object({ +export const zIntStorageSelfdestructDiffs = z.object({ address: z.optional(z.string()), block_number: z.optional( z @@ -11446,7 +11627,8 @@ export const zIntStorageSlotDiff = z.object({ z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) ) ), - effective_bytes_from: z.optional( + from_value: z.optional(z.string()), + internal_index: z.optional( z .int() .check( @@ -11454,7 +11636,10 @@ export const zIntStorageSlotDiff = z.object({ z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) ) ), - effective_bytes_to: z.optional( + slot: z.optional(z.string()), + to_value: z.optional(z.string()), + transaction_hash: z.optional(z.string()), + transaction_index: z.optional( z .int() .check( @@ -11462,7 +11647,6 @@ export const zIntStorageSlotDiff = z.object({ z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) ) ), - slot_key: z.optional(z.string()), updated_date_time: z.optional( z .int() @@ -11474,13 +11658,13 @@ export const zIntStorageSlotDiff = z.object({ }); /** - * Response for getting a single int_storage_slot_diff record + * Response for getting a single int_storage_selfdestruct_diffs record */ -export const zGetIntStorageSlotDiffResponse = z.object({ - item: z.optional(zIntStorageSlotDiff), +export const zGetIntStorageSelfdestructDiffsResponse = z.object({ + item: z.optional(zIntStorageSelfdestructDiffs), }); -export const zIntStorageSlotDiffByAddressSlot = z.object({ +export const zIntStorageSlotDiff = z.object({ address: z.optional(z.string()), block_number: z.optional( z @@ -11518,13 +11702,13 @@ export const zIntStorageSlotDiffByAddressSlot = z.object({ }); /** - * Response for getting a single int_storage_slot_diff_by_address_slot record + * Response for getting a single int_storage_slot_diff record */ -export const zGetIntStorageSlotDiffByAddressSlotResponse = z.object({ - item: z.optional(zIntStorageSlotDiffByAddressSlot), +export const zGetIntStorageSlotDiffResponse = z.object({ + item: z.optional(zIntStorageSlotDiff), }); -export const zIntStorageSlotExpiry1m = z.object({ +export const zIntStorageSlotDiffByAddressSlot = z.object({ address: z.optional(z.string()), block_number: z.optional( z @@ -11534,7 +11718,7 @@ export const zIntStorageSlotExpiry1m = z.object({ z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) ) ), - effective_bytes: z.optional( + effective_bytes_from: z.optional( z .int() .check( @@ -11542,8 +11726,7 @@ export const zIntStorageSlotExpiry1m = z.object({ z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) ) ), - slot_key: z.optional(z.string()), - touch_block: z.optional( + effective_bytes_to: z.optional( z .int() .check( @@ -11551,6 +11734,7 @@ export const zIntStorageSlotExpiry1m = z.object({ z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) ) ), + slot_key: z.optional(z.string()), updated_date_time: z.optional( z .int() @@ -11562,13 +11746,13 @@ export const zIntStorageSlotExpiry1m = z.object({ }); /** - * Response for getting a single int_storage_slot_expiry_1m record + * Response for getting a single int_storage_slot_diff_by_address_slot record */ -export const zGetIntStorageSlotExpiry1mResponse = z.object({ - item: z.optional(zIntStorageSlotExpiry1m), +export const zGetIntStorageSlotDiffByAddressSlotResponse = z.object({ + item: z.optional(zIntStorageSlotDiffByAddressSlot), }); -export const zIntStorageSlotExpiry6m = z.object({ +export const zIntStorageSlotExpiry1m = z.object({ address: z.optional(z.string()), block_number: z.optional( z @@ -11606,13 +11790,13 @@ export const zIntStorageSlotExpiry6m = z.object({ }); /** - * Response for getting a single int_storage_slot_expiry_6m record + * Response for getting a single int_storage_slot_expiry_1m record */ -export const zGetIntStorageSlotExpiry6mResponse = z.object({ - item: z.optional(zIntStorageSlotExpiry6m), +export const zGetIntStorageSlotExpiry1mResponse = z.object({ + item: z.optional(zIntStorageSlotExpiry1m), }); -export const zIntStorageSlotExpiry12m = z.object({ +export const zIntStorageSlotExpiry6m = z.object({ address: z.optional(z.string()), block_number: z.optional( z @@ -11650,13 +11834,13 @@ export const zIntStorageSlotExpiry12m = z.object({ }); /** - * Response for getting a single int_storage_slot_expiry_12m record + * Response for getting a single int_storage_slot_expiry_6m record */ -export const zGetIntStorageSlotExpiry12mResponse = z.object({ - item: z.optional(zIntStorageSlotExpiry12m), +export const zGetIntStorageSlotExpiry6mResponse = z.object({ + item: z.optional(zIntStorageSlotExpiry6m), }); -export const zIntStorageSlotExpiry18m = z.object({ +export const zIntStorageSlotExpiry12m = z.object({ address: z.optional(z.string()), block_number: z.optional( z @@ -11694,13 +11878,13 @@ export const zIntStorageSlotExpiry18m = z.object({ }); /** - * Response for getting a single int_storage_slot_expiry_18m record + * Response for getting a single int_storage_slot_expiry_12m record */ -export const zGetIntStorageSlotExpiry18mResponse = z.object({ - item: z.optional(zIntStorageSlotExpiry18m), +export const zGetIntStorageSlotExpiry12mResponse = z.object({ + item: z.optional(zIntStorageSlotExpiry12m), }); -export const zIntStorageSlotExpiry24m = z.object({ +export const zIntStorageSlotExpiry18m = z.object({ address: z.optional(z.string()), block_number: z.optional( z @@ -11738,52 +11922,96 @@ export const zIntStorageSlotExpiry24m = z.object({ }); /** - * Response for getting a single int_storage_slot_expiry_24m record - */ -export const zGetIntStorageSlotExpiry24mResponse = z.object({ - item: z.optional(zIntStorageSlotExpiry24m), -}); - -export const zIntStorageSlotNextTouch = z.object({ - address: z.optional(z.string()), - block_number: z.optional( - z - .int() - .check( - z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), - z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) - ) - ), - next_touch_block: z.optional( - z.union([ - z - .int() - .check( - z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), - z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) - ), - z.null(), - ]) - ), - slot_key: z.optional(z.string()), - updated_date_time: z.optional( - z - .int() - .check( - z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), - z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) - ) - ), -}); - -/** - * Response for getting a single int_storage_slot_next_touch record + * Response for getting a single int_storage_slot_expiry_18m record */ -export const zGetIntStorageSlotNextTouchResponse = z.object({ - item: z.optional(zIntStorageSlotNextTouch), +export const zGetIntStorageSlotExpiry18mResponse = z.object({ + item: z.optional(zIntStorageSlotExpiry18m), }); -export const zIntStorageSlotReactivation1m = z.object({ +export const zIntStorageSlotExpiry24m = z.object({ + address: z.optional(z.string()), + block_number: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + effective_bytes: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + slot_key: z.optional(z.string()), + touch_block: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), +}); + +/** + * Response for getting a single int_storage_slot_expiry_24m record + */ +export const zGetIntStorageSlotExpiry24mResponse = z.object({ + item: z.optional(zIntStorageSlotExpiry24m), +}); + +export const zIntStorageSlotNextTouch = z.object({ + address: z.optional(z.string()), + block_number: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + next_touch_block: z.optional( + z.union([ + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ), + z.null(), + ]) + ), + slot_key: z.optional(z.string()), + updated_date_time: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), +}); + +/** + * Response for getting a single int_storage_slot_next_touch record + */ +export const zGetIntStorageSlotNextTouchResponse = z.object({ + item: z.optional(zIntStorageSlotNextTouch), +}); + +export const zIntStorageSlotReactivation1m = z.object({ address: z.optional(z.string()), block_number: z.optional( z @@ -13578,6 +13806,14 @@ export const zListFctNodeActiveLast24hResponse = z.object({ next_page_token: z.optional(z.string()), }); +/** + * Response for listing fct_node_cpu_utilization records + */ +export const zListFctNodeCpuUtilizationResponse = z.object({ + fct_node_cpu_utilization: z.optional(z.array(zFctNodeCpuUtilization)), + next_page_token: z.optional(z.string()), +}); + /** * Response for listing fct_opcode_gas_by_opcode_daily records */ @@ -13890,6 +14126,22 @@ export const zListIntBlockProposerCanonicalResponse = z.object({ next_page_token: z.optional(z.string()), }); +/** + * Response for listing int_contract_creation records + */ +export const zListIntContractCreationResponse = z.object({ + int_contract_creation: z.optional(z.array(zIntContractCreation)), + next_page_token: z.optional(z.string()), +}); + +/** + * Response for listing int_contract_selfdestruct records + */ +export const zListIntContractSelfdestructResponse = z.object({ + int_contract_selfdestruct: z.optional(z.array(zIntContractSelfdestruct)), + next_page_token: z.optional(z.string()), +}); + /** * Response for listing int_contract_storage_expiry_1m records */ @@ -14051,10 +14303,12 @@ export const zListIntEngineGetBlobsResponse = z.object({ }); /** - * Response for listing int_engine_new_payload_fastest records + * Response for listing int_engine_new_payload_fastest_execution_by_node_class records */ -export const zListIntEngineNewPayloadFastestResponse = z.object({ - int_engine_new_payload_fastest: z.optional(z.array(zIntEngineNewPayloadFastest)), +export const zListIntEngineNewPayloadFastestExecutionByNodeClassResponse = z.object({ + int_engine_new_payload_fastest_execution_by_node_class: z.optional( + z.array(zIntEngineNewPayloadFastestExecutionByNodeClass) + ), next_page_token: z.optional(z.string()), }); @@ -14074,6 +14328,14 @@ export const zListIntExecutionBlockByDateResponse = z.object({ next_page_token: z.optional(z.string()), }); +/** + * Response for listing int_storage_selfdestruct_diffs records + */ +export const zListIntStorageSelfdestructDiffsResponse = z.object({ + int_storage_selfdestruct_diffs: z.optional(z.array(zIntStorageSelfdestructDiffs)), + next_page_token: z.optional(z.string()), +}); + /** * Response for listing int_storage_slot_diff_by_address_slot records */ @@ -68705,29 +68967,575 @@ export const zFctNodeActiveLast24hServiceGetData = z.object({ */ export const zFctNodeActiveLast24hServiceGetResponse = zGetFctNodeActiveLast24hResponse; -export const zFctOpcodeGasByOpcodeDailyServiceListData = z.object({ +export const zFctNodeCpuUtilizationServiceListData = z.object({ body: z.optional(z.never()), path: z.optional(z.never()), query: z.optional( z.object({ - day_start_date_eq: z.optional(z.string()), - day_start_date_ne: z.optional(z.string()), - day_start_date_contains: z.optional(z.string()), - day_start_date_starts_with: z.optional(z.string()), - day_start_date_ends_with: z.optional(z.string()), - day_start_date_like: z.optional(z.string()), - day_start_date_not_like: z.optional(z.string()), - day_start_date_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), - day_start_date_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), - opcode_eq: z.optional(z.string()), - opcode_ne: z.optional(z.string()), - opcode_contains: z.optional(z.string()), - opcode_starts_with: z.optional(z.string()), - opcode_ends_with: z.optional(z.string()), - opcode_like: z.optional(z.string()), - opcode_not_like: z.optional(z.string()), - opcode_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), - opcode_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + wallclock_slot_start_date_time_eq: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_ne: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_lt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_lte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_gt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_gte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_between_min: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_between_max_value: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_in_values: z.optional(z.string().check(z.regex(/^-?\d+(,-?\d+)*$/))), + wallclock_slot_start_date_time_not_in_values: z.optional(z.string().check(z.regex(/^-?\d+(,-?\d+)*$/))), + meta_client_name_eq: z.optional(z.string()), + meta_client_name_ne: z.optional(z.string()), + meta_client_name_contains: z.optional(z.string()), + meta_client_name_starts_with: z.optional(z.string()), + meta_client_name_ends_with: z.optional(z.string()), + meta_client_name_like: z.optional(z.string()), + meta_client_name_not_like: z.optional(z.string()), + meta_client_name_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + meta_client_name_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + client_type_eq: z.optional(z.string()), + client_type_ne: z.optional(z.string()), + client_type_contains: z.optional(z.string()), + client_type_starts_with: z.optional(z.string()), + client_type_ends_with: z.optional(z.string()), + client_type_like: z.optional(z.string()), + client_type_not_like: z.optional(z.string()), + client_type_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + client_type_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + pid_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + pid_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + window_start_eq: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_ne: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_lt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_lte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_gt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_gte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_between_min: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_between_max_value: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_in_values: z.optional(z.string().check(z.regex(/^-?\d+(,-?\d+)*$/))), + window_start_not_in_values: z.optional(z.string().check(z.regex(/^-?\d+(,-?\d+)*$/))), + updated_date_time_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + updated_date_time_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + wallclock_slot_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + wallclock_slot_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + meta_network_name_eq: z.optional(z.string()), + meta_network_name_ne: z.optional(z.string()), + meta_network_name_contains: z.optional(z.string()), + meta_network_name_starts_with: z.optional(z.string()), + meta_network_name_ends_with: z.optional(z.string()), + meta_network_name_like: z.optional(z.string()), + meta_network_name_not_like: z.optional(z.string()), + meta_network_name_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + meta_network_name_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + system_cores_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + system_cores_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + system_cores_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + system_cores_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + system_cores_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + system_cores_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + system_cores_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + system_cores_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + system_cores_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + system_cores_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + mean_core_pct_value: z.optional(z.number()), + min_core_pct_value: z.optional(z.number()), + max_core_pct_value: z.optional(z.number()), + max_single_core_pct_value: z.optional(z.number()), + node_class_eq: z.optional(z.string()), + node_class_ne: z.optional(z.string()), + node_class_contains: z.optional(z.string()), + node_class_starts_with: z.optional(z.string()), + node_class_ends_with: z.optional(z.string()), + node_class_like: z.optional(z.string()), + node_class_not_like: z.optional(z.string()), + node_class_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + node_class_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + page_size: z.optional( + z + .int() + .check( + z.minimum(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }), + z.maximum(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }) + ) + ), + page_token: z.optional(z.string()), + order_by: z.optional(z.string()), + }) + ), +}); + +/** + * OK + */ +export const zFctNodeCpuUtilizationServiceListResponse = zListFctNodeCpuUtilizationResponse; + +export const zFctNodeCpuUtilizationServiceGetData = z.object({ + body: z.optional(z.never()), + path: z.object({ + wallclock_slot_start_date_time: z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ), + }), + query: z.optional(z.never()), +}); + +/** + * OK + */ +export const zFctNodeCpuUtilizationServiceGetResponse = zGetFctNodeCpuUtilizationResponse; + +export const zFctOpcodeGasByOpcodeDailyServiceListData = z.object({ + body: z.optional(z.never()), + path: z.optional(z.never()), + query: z.optional( + z.object({ + day_start_date_eq: z.optional(z.string()), + day_start_date_ne: z.optional(z.string()), + day_start_date_contains: z.optional(z.string()), + day_start_date_starts_with: z.optional(z.string()), + day_start_date_ends_with: z.optional(z.string()), + day_start_date_like: z.optional(z.string()), + day_start_date_not_like: z.optional(z.string()), + day_start_date_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + day_start_date_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + opcode_eq: z.optional(z.string()), + opcode_ne: z.optional(z.string()), + opcode_contains: z.optional(z.string()), + opcode_starts_with: z.optional(z.string()), + opcode_ends_with: z.optional(z.string()), + opcode_like: z.optional(z.string()), + opcode_not_like: z.optional(z.string()), + opcode_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + opcode_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), updated_date_time_eq: z.optional( z .int() @@ -86183,6 +86991,778 @@ export const zIntBlockProposerCanonicalServiceGetData = z.object({ */ export const zIntBlockProposerCanonicalServiceGetResponse = zGetIntBlockProposerCanonicalResponse; +export const zIntContractCreationServiceListData = z.object({ + body: z.optional(z.never()), + path: z.optional(z.never()), + query: z.optional( + z.object({ + block_number_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + block_number_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + contract_address_eq: z.optional(z.string()), + contract_address_ne: z.optional(z.string()), + contract_address_contains: z.optional(z.string()), + contract_address_starts_with: z.optional(z.string()), + contract_address_ends_with: z.optional(z.string()), + contract_address_like: z.optional(z.string()), + contract_address_not_like: z.optional(z.string()), + contract_address_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + contract_address_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + transaction_hash_eq: z.optional(z.string()), + transaction_hash_ne: z.optional(z.string()), + transaction_hash_contains: z.optional(z.string()), + transaction_hash_starts_with: z.optional(z.string()), + transaction_hash_ends_with: z.optional(z.string()), + transaction_hash_like: z.optional(z.string()), + transaction_hash_not_like: z.optional(z.string()), + transaction_hash_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + transaction_hash_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + updated_date_time_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + updated_date_time_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + transaction_index_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + transaction_index_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + internal_index_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + internal_index_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + deployer_eq: z.optional(z.string()), + deployer_ne: z.optional(z.string()), + deployer_contains: z.optional(z.string()), + deployer_starts_with: z.optional(z.string()), + deployer_ends_with: z.optional(z.string()), + deployer_like: z.optional(z.string()), + deployer_not_like: z.optional(z.string()), + deployer_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + deployer_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + factory_eq: z.optional(z.string()), + factory_ne: z.optional(z.string()), + factory_contains: z.optional(z.string()), + factory_starts_with: z.optional(z.string()), + factory_ends_with: z.optional(z.string()), + factory_like: z.optional(z.string()), + factory_not_like: z.optional(z.string()), + factory_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + factory_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + init_code_hash_eq: z.optional(z.string()), + init_code_hash_ne: z.optional(z.string()), + init_code_hash_contains: z.optional(z.string()), + init_code_hash_starts_with: z.optional(z.string()), + init_code_hash_ends_with: z.optional(z.string()), + init_code_hash_like: z.optional(z.string()), + init_code_hash_not_like: z.optional(z.string()), + init_code_hash_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + init_code_hash_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + page_size: z.optional( + z + .int() + .check( + z.minimum(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }), + z.maximum(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }) + ) + ), + page_token: z.optional(z.string()), + order_by: z.optional(z.string()), + }) + ), +}); + +/** + * OK + */ +export const zIntContractCreationServiceListResponse = zListIntContractCreationResponse; + +export const zIntContractCreationServiceGetData = z.object({ + body: z.optional(z.never()), + path: z.object({ + block_number: z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ), + }), + query: z.optional(z.never()), +}); + +/** + * OK + */ +export const zIntContractCreationServiceGetResponse = zGetIntContractCreationResponse; + +export const zIntContractSelfdestructServiceListData = z.object({ + body: z.optional(z.never()), + path: z.optional(z.never()), + query: z.optional( + z.object({ + block_number_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + block_number_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + transaction_index_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + transaction_index_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + internal_index_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + internal_index_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + address_eq: z.optional(z.string()), + address_ne: z.optional(z.string()), + address_contains: z.optional(z.string()), + address_starts_with: z.optional(z.string()), + address_ends_with: z.optional(z.string()), + address_like: z.optional(z.string()), + address_not_like: z.optional(z.string()), + address_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + address_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + updated_date_time_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + updated_date_time_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + transaction_hash_eq: z.optional(z.string()), + transaction_hash_ne: z.optional(z.string()), + transaction_hash_contains: z.optional(z.string()), + transaction_hash_starts_with: z.optional(z.string()), + transaction_hash_ends_with: z.optional(z.string()), + transaction_hash_like: z.optional(z.string()), + transaction_hash_not_like: z.optional(z.string()), + transaction_hash_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + transaction_hash_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + beneficiary_eq: z.optional(z.string()), + beneficiary_ne: z.optional(z.string()), + beneficiary_contains: z.optional(z.string()), + beneficiary_starts_with: z.optional(z.string()), + beneficiary_ends_with: z.optional(z.string()), + beneficiary_like: z.optional(z.string()), + beneficiary_not_like: z.optional(z.string()), + beneficiary_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + beneficiary_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + value_transferred_eq: z.optional(z.string()), + value_transferred_ne: z.optional(z.string()), + value_transferred_contains: z.optional(z.string()), + value_transferred_starts_with: z.optional(z.string()), + value_transferred_ends_with: z.optional(z.string()), + value_transferred_like: z.optional(z.string()), + value_transferred_not_like: z.optional(z.string()), + value_transferred_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + value_transferred_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + ephemeral_eq: z.optional(z.boolean()), + ephemeral_ne: z.optional(z.boolean()), + storage_cleared_eq: z.optional(z.boolean()), + storage_cleared_ne: z.optional(z.boolean()), + creation_block_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + creation_block_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + creation_block_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + creation_block_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + creation_block_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + creation_block_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + creation_block_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + creation_block_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + creation_block_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + creation_block_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + creation_transaction_hash_eq: z.optional(z.string()), + creation_transaction_hash_ne: z.optional(z.string()), + creation_transaction_hash_contains: z.optional(z.string()), + creation_transaction_hash_starts_with: z.optional(z.string()), + creation_transaction_hash_ends_with: z.optional(z.string()), + creation_transaction_hash_like: z.optional(z.string()), + creation_transaction_hash_not_like: z.optional(z.string()), + creation_transaction_hash_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + creation_transaction_hash_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + page_size: z.optional( + z + .int() + .check( + z.minimum(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }), + z.maximum(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }) + ) + ), + page_token: z.optional(z.string()), + order_by: z.optional(z.string()), + }) + ), +}); + +/** + * OK + */ +export const zIntContractSelfdestructServiceListResponse = zListIntContractSelfdestructResponse; + +export const zIntContractSelfdestructServiceGetData = z.object({ + body: z.optional(z.never()), + path: z.object({ + block_number: z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ), + }), + query: z.optional(z.never()), +}); + +/** + * OK + */ +export const zIntContractSelfdestructServiceGetResponse = zGetIntContractSelfdestructResponse; + export const zIntContractStorageExpiry1mServiceListData = z.object({ body: z.optional(z.never()), path: z.optional(z.never()), @@ -98621,7 +100201,7 @@ export const zIntEngineNewPayloadServiceGetData = z.object({ */ export const zIntEngineNewPayloadServiceGetResponse = zGetIntEngineNewPayloadResponse; -export const zIntEngineNewPayloadFastestServiceListData = z.object({ +export const zIntEngineNewPayloadFastestExecutionByNodeClassServiceListData = z.object({ body: z.optional(z.never()), path: z.optional(z.never()), query: z.optional( @@ -99100,9 +100680,10 @@ export const zIntEngineNewPayloadFastestServiceListData = z.object({ /** * OK */ -export const zIntEngineNewPayloadFastestServiceListResponse = zListIntEngineNewPayloadFastestResponse; +export const zIntEngineNewPayloadFastestExecutionByNodeClassServiceListResponse = + zListIntEngineNewPayloadFastestExecutionByNodeClassResponse; -export const zIntEngineNewPayloadFastestServiceGetData = z.object({ +export const zIntEngineNewPayloadFastestExecutionByNodeClassServiceGetData = z.object({ body: z.optional(z.never()), path: z.object({ slot_start_date_time: z @@ -99118,7 +100699,8 @@ export const zIntEngineNewPayloadFastestServiceGetData = z.object({ /** * OK */ -export const zIntEngineNewPayloadFastestServiceGetResponse = zGetIntEngineNewPayloadFastestResponse; +export const zIntEngineNewPayloadFastestExecutionByNodeClassServiceGetResponse = + zGetIntEngineNewPayloadFastestExecutionByNodeClassResponse; export const zIntExecutionBlockByDateServiceListData = z.object({ body: z.optional(z.never()), @@ -99412,6 +100994,357 @@ export const zIntExecutionBlockByDateServiceGetData = z.object({ */ export const zIntExecutionBlockByDateServiceGetResponse = zGetIntExecutionBlockByDateResponse; +export const zIntStorageSelfdestructDiffsServiceListData = z.object({ + body: z.optional(z.never()), + path: z.optional(z.never()), + query: z.optional( + z.object({ + block_number_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + block_number_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + block_number_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + transaction_hash_eq: z.optional(z.string()), + transaction_hash_ne: z.optional(z.string()), + transaction_hash_contains: z.optional(z.string()), + transaction_hash_starts_with: z.optional(z.string()), + transaction_hash_ends_with: z.optional(z.string()), + transaction_hash_like: z.optional(z.string()), + transaction_hash_not_like: z.optional(z.string()), + transaction_hash_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + transaction_hash_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + internal_index_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + internal_index_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + internal_index_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + slot_eq: z.optional(z.string()), + slot_ne: z.optional(z.string()), + slot_contains: z.optional(z.string()), + slot_starts_with: z.optional(z.string()), + slot_ends_with: z.optional(z.string()), + slot_like: z.optional(z.string()), + slot_not_like: z.optional(z.string()), + slot_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + slot_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + updated_date_time_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + updated_date_time_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + transaction_index_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + transaction_index_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + transaction_index_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + address_eq: z.optional(z.string()), + address_ne: z.optional(z.string()), + address_contains: z.optional(z.string()), + address_starts_with: z.optional(z.string()), + address_ends_with: z.optional(z.string()), + address_like: z.optional(z.string()), + address_not_like: z.optional(z.string()), + address_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + address_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + from_value_eq: z.optional(z.string()), + from_value_ne: z.optional(z.string()), + from_value_contains: z.optional(z.string()), + from_value_starts_with: z.optional(z.string()), + from_value_ends_with: z.optional(z.string()), + from_value_like: z.optional(z.string()), + from_value_not_like: z.optional(z.string()), + from_value_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + from_value_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + to_value_eq: z.optional(z.string()), + to_value_ne: z.optional(z.string()), + to_value_contains: z.optional(z.string()), + to_value_starts_with: z.optional(z.string()), + to_value_ends_with: z.optional(z.string()), + to_value_like: z.optional(z.string()), + to_value_not_like: z.optional(z.string()), + to_value_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + to_value_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + page_size: z.optional( + z + .int() + .check( + z.minimum(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }), + z.maximum(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }) + ) + ), + page_token: z.optional(z.string()), + order_by: z.optional(z.string()), + }) + ), +}); + +/** + * OK + */ +export const zIntStorageSelfdestructDiffsServiceListResponse = zListIntStorageSelfdestructDiffsResponse; + +export const zIntStorageSelfdestructDiffsServiceGetData = z.object({ + body: z.optional(z.never()), + path: z.object({ + block_number: z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ), + }), + query: z.optional(z.never()), +}); + +/** + * OK + */ +export const zIntStorageSelfdestructDiffsServiceGetResponse = zGetIntStorageSelfdestructDiffsResponse; + export const zIntStorageSlotDiffServiceListData = z.object({ body: z.optional(z.never()), path: z.optional(z.never()), diff --git a/src/pages/ethereum/slots/DetailPage.tsx b/src/pages/ethereum/slots/DetailPage.tsx index 76c5702d8..b53ae8913 100644 --- a/src/pages/ethereum/slots/DetailPage.tsx +++ b/src/pages/ethereum/slots/DetailPage.tsx @@ -41,6 +41,7 @@ import { SlotDetailSkeleton } from './components/SlotDetailSkeleton'; import { EngineTimingsCard } from './components/EngineTimingsCard'; import { SlotProgressTimeline } from './components/SlotProgressTimeline'; import { useSlotEngineTimings } from './hooks/useSlotEngineTimings'; +import { NodeResourcesPanel } from './components/NodeResources'; /** * Detail page for a specific slot. @@ -143,6 +144,7 @@ export function DetailPage(): JSX.Element { { id: 'blobs' }, { id: 'execution' }, { id: 'mev' }, + { id: 'resources' }, ]); // Validate slot number @@ -393,6 +395,7 @@ export function DetailPage(): JSX.Element { Blobs Execution MEV + Node Resources @@ -1120,6 +1123,14 @@ export function DetailPage(): JSX.Element { )} + + {/* Node Resources Tab */} + + + diff --git a/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx b/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx new file mode 100644 index 000000000..ec6a5d9be --- /dev/null +++ b/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx @@ -0,0 +1,317 @@ +import { type JSX, useMemo } from 'react'; +import { PopoutCard } from '@/components/Layout/PopoutCard'; +import { MultiLineChart } from '@/components/Charts/MultiLine'; +import type { SeriesData, MarkLineConfig } from '@/components/Charts/MultiLine/MultiLine.types'; +import { getDataVizColors } from '@/utils'; +import { ClientLogo } from '@/components/Ethereum/ClientLogo'; +import type { FctNodeCpuUtilization } from '@/api/types.gen'; +import type { CpuMetric } from './NodeResourcesPanel'; + +const CL_CLIENTS = new Set(['lighthouse', 'lodestar', 'nimbus', 'prysm', 'teku', 'grandine']); +const EL_CLIENTS = new Set(['besu', 'erigon', 'geth', 'nethermind', 'reth']); + +function getClientLayer(clientType: string): 'CL' | 'EL' | null { + const lower = clientType.toLowerCase(); + if (CL_CLIENTS.has(lower)) return 'CL'; + if (EL_CLIENTS.has(lower)) return 'EL'; + return null; +} + +/** Convert API microsecond timestamp to seconds */ +function usToSeconds(us: number): number { + return us / 1_000_000; +} + +/** Get the normalized metric value (0-100% of total system) from a data point */ +function getMetricValue(d: FctNodeCpuUtilization, metric: CpuMetric): number { + const cores = d.system_cores ?? 1; + const divisor = cores > 0 ? cores : 1; + switch (metric) { + case 'min': + return (d.min_core_pct ?? 0) / divisor; + case 'max': + return (d.max_core_pct ?? 0) / divisor; + case 'mean': + default: + return (d.mean_core_pct ?? 0) / divisor; + } +} + +const METRIC_LABELS: Record = { + mean: 'Mean', + min: 'Min', + max: 'Max', +}; + +interface BlockArrival { + seen_slot_start_diff: number; + node_id: string; +} + +interface CpuUtilizationChartProps { + data: FctNodeCpuUtilization[]; + selectedNode: string | null; + blockPropagationData: BlockArrival[]; + metric: CpuMetric; +} + +export function CpuUtilizationChart({ + data, + selectedNode, + blockPropagationData, + metric, +}: CpuUtilizationChartProps): JSX.Element { + const { CHART_CATEGORICAL_COLORS } = getDataVizColors(); + + const { series, markLines, clClient, elClient } = useMemo(() => { + if (data.length === 0) { + return { series: [] as SeriesData[], markLines: [] as MarkLineConfig[], clClient: '', elClient: '' }; + } + + // Derive slot start time from data (microseconds) + const slotStartUs = Math.min(...data.map(d => d.wallclock_slot_start_date_time ?? 0).filter(v => v > 0)); + + const chartSeries: SeriesData[] = []; + let resolvedClClient = ''; + let resolvedElClient = ''; + + // Bucket size for time aggregation (seconds) + const BUCKET_SIZE = 0.25; + const toBucket = (offsetSec: number): number => Math.round(offsetSec / BUCKET_SIZE) * BUCKET_SIZE; + + const buildLine = ( + items: FctNodeCpuUtilization[], + label: string, + color: string, + getValue: CpuMetric | ((d: FctNodeCpuUtilization) => number), + opts?: { + lineWidth?: number; + showArea?: boolean; + areaOpacity?: number; + lineStyle?: 'solid' | 'dashed' | 'dotted'; + } + ): void => { + const extractValue = + typeof getValue === 'function' ? getValue : (d: FctNodeCpuUtilization) => getMetricValue(d, getValue); + + const byBucket = new Map(); + items.forEach(d => { + const offset = usToSeconds((d.window_start ?? 0) - slotStartUs); + const bucket = toBucket(offset); + if (bucket < 0 || bucket > 12) return; + if (!byBucket.has(bucket)) byBucket.set(bucket, []); + byBucket.get(bucket)!.push(extractValue(d)); + }); + + const points = Array.from(byBucket.entries()) + .sort(([a], [b]) => a - b) + .map(([offset, values]) => [offset, values.reduce((s, v) => s + v, 0) / values.length] as [number, number]); + + if (points.length > 0) { + chartSeries.push({ + name: label, + data: points, + color, + lineWidth: opts?.lineWidth ?? 2, + showArea: opts?.showArea ?? true, + areaOpacity: opts?.areaOpacity ?? 0.08, + lineStyle: opts?.lineStyle, + }); + } + }; + + if (selectedNode) { + const nodeData = data.filter(d => d.meta_client_name === selectedNode); + const clData = nodeData.filter(d => getClientLayer(d.client_type ?? '') === 'CL'); + const elData = nodeData.filter(d => getClientLayer(d.client_type ?? '') === 'EL'); + + resolvedClClient = clData[0]?.client_type ?? ''; + resolvedElClient = elData[0]?.client_type ?? ''; + + const clLabel = resolvedClClient || 'CL'; + const elLabel = resolvedElClient || 'EL'; + const clColor = CHART_CATEGORICAL_COLORS[0]; + const elColor = CHART_CATEGORICAL_COLORS[1]; + + const coreExtract = (d: FctNodeCpuUtilization) => Math.min(d.max_core_pct ?? 0, 100); + + // CL system utilization: mean (solid), min (dotted), max (dashed) + buildLine(clData, `${clLabel} sys mean`, clColor, 'mean', { lineWidth: 2, showArea: true, areaOpacity: 0.06 }); + buildLine(clData, `${clLabel} sys min`, clColor, 'min', { + lineWidth: 1.5, + showArea: false, + lineStyle: 'dotted', + }); + buildLine(clData, `${clLabel} sys max`, clColor, 'max', { + lineWidth: 1.5, + showArea: false, + lineStyle: 'dashed', + }); + + // EL system utilization: mean (solid), min (dotted), max (dashed) + buildLine(elData, `${elLabel} sys mean`, elColor, 'mean', { lineWidth: 2, showArea: true, areaOpacity: 0.06 }); + buildLine(elData, `${elLabel} sys min`, elColor, 'min', { + lineWidth: 1.5, + showArea: false, + lineStyle: 'dotted', + }); + buildLine(elData, `${elLabel} sys max`, elColor, 'max', { + lineWidth: 1.5, + showArea: false, + lineStyle: 'dashed', + }); + + // Hottest single core per client (raw, not divided by system_cores) + const singleCoreColor = CHART_CATEGORICAL_COLORS[2] ?? '#e5a00d'; + buildLine(clData, `${clLabel} hottest core`, singleCoreColor, coreExtract, { + lineWidth: 1.5, + showArea: false, + lineStyle: 'dashed', + }); + buildLine(elData, `${elLabel} hottest core`, singleCoreColor, coreExtract, { + lineWidth: 1.5, + showArea: false, + lineStyle: 'dotted', + }); + } else { + const clData = data.filter(d => getClientLayer(d.client_type ?? '') === 'CL'); + const elData = data.filter(d => getClientLayer(d.client_type ?? '') === 'EL'); + + buildLine(clData, 'Consensus Layer', CHART_CATEGORICAL_COLORS[0], metric); + buildLine(elData, 'Execution Layer', CHART_CATEGORICAL_COLORS[1], metric); + } + + // Block arrival markLines + const chartMarkLines: MarkLineConfig[] = []; + + if (blockPropagationData.length > 0) { + if (selectedNode) { + const shortNodeName = selectedNode.split('/').pop() ?? selectedNode; + const nodeArrival = blockPropagationData.find( + p => + p.node_id === shortNodeName || + p.node_id === selectedNode || + shortNodeName.includes(p.node_id) || + p.node_id.includes(shortNodeName) + ); + if (nodeArrival) { + chartMarkLines.push({ + xValue: nodeArrival.seen_slot_start_diff / 1000, + label: 'Block Arrival', + color: 'var(--color-warning)', + lineStyle: 'dashed', + lineWidth: 1, + }); + } else { + const arrivalTimes = blockPropagationData.map(p => p.seen_slot_start_diff).sort((a, b) => a - b); + const p50Index = Math.floor(arrivalTimes.length * 0.5); + chartMarkLines.push({ + xValue: arrivalTimes[p50Index] / 1000, + label: 'Block p50', + color: 'var(--color-warning)', + lineStyle: 'dotted', + lineWidth: 1, + }); + } + } else { + const arrivalTimes = blockPropagationData.map(p => p.seen_slot_start_diff).sort((a, b) => a - b); + if (arrivalTimes.length > 0) { + const p50Index = Math.floor(arrivalTimes.length * 0.5); + chartMarkLines.push({ + xValue: arrivalTimes[p50Index] / 1000, + label: 'Block p50', + color: 'var(--color-warning)', + lineStyle: 'dashed', + lineWidth: 1, + }); + } + } + } + + return { series: chartSeries, markLines: chartMarkLines, clClient: resolvedClClient, elClient: resolvedElClient }; + }, [data, selectedNode, blockPropagationData, metric, CHART_CATEGORICAL_COLORS]); + + const nodeCount = new Set(data.map(d => d.meta_client_name)).size; + const shortNodeName = selectedNode?.split('/').pop() ?? ''; + + const subtitle = selectedNode + ? `${shortNodeName} · sys% = total system, hottest core = single core peak` + : `${METRIC_LABELS[metric]} across ${nodeCount} nodes · % of total system`; + + const headerActions = + selectedNode && (clClient || elClient) ? ( +
+ {clClient && } + {elClient && } +
+ ) : undefined; + + if (data.length === 0) { + return ( + + {({ inModal }) => ( +
+
+

No CPU utilization data available for this slot

+
+
+ )} +
+ ); + } + + return ( + + {({ inModal }) => ( + `${v}s`, + }} + yAxis={{ + name: 'CPU %', + min: 0, + formatter: (v: number) => `${v.toFixed(1)}%`, + }} + height={inModal ? 500 : 350} + showLegend + legendPosition="bottom" + markLines={markLines} + syncGroup="slot-time" + valueDecimals={1} + tooltipFormatter={(params: unknown) => { + const items = Array.isArray(params) ? params : [params]; + if (items.length === 0) return ''; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const first = items[0] as any; + const xVal = Array.isArray(first.value) ? first.value[0] : first.axisValue; + const timeStr = typeof xVal === 'number' ? `${xVal.toFixed(3)}s` : `${xVal}s`; + + let html = `
`; + html += `
${timeStr}
`; + + for (const item of items) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const p = item as any; + const val = Array.isArray(p.value) ? p.value[1] : p.value; + if (val == null) continue; + html += `
`; + html += `${p.marker}`; + html += `${p.seriesName}`; + html += `${Number(val).toFixed(1)}%`; + html += `
`; + } + + html += `
`; + return html; + }} + /> + )} +
+ ); +} diff --git a/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx b/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx new file mode 100644 index 000000000..95311373d --- /dev/null +++ b/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx @@ -0,0 +1,210 @@ +import { type JSX, useState, useMemo, useCallback } from 'react'; +import { useSearch, useNavigate } from '@tanstack/react-router'; +import { InformationCircleIcon } from '@heroicons/react/24/outline'; +import { Card } from '@/components/Layout/Card'; +import { Checkbox } from '@/components/Forms/Checkbox'; +import { SelectMenu } from '@/components/Forms/SelectMenu'; +import { ReferenceNodesInfoDialog } from '@/pages/ethereum/execution/timings/components/ReferenceNodesInfoDialog'; +import { extractClusterFromNodeName } from '@/constants/eip7870'; +import { useSlotNodeResources } from '../../hooks/useSlotNodeResources'; +import { NodeSelector, type NodeClientInfo } from './NodeSelector'; +import { CpuUtilizationChart } from './CpuUtilizationChart'; + +export type CpuMetric = 'mean' | 'min' | 'max'; + +const CL_CLIENTS = new Set(['lighthouse', 'lodestar', 'nimbus', 'prysm', 'teku', 'grandine']); +const EL_CLIENTS = new Set(['besu', 'erigon', 'geth', 'nethermind', 'reth']); + +interface BlockArrival { + seen_slot_start_diff: number; + node_id: string; +} + +interface NodeResourcesPanelProps { + slot: number; + blockPropagationData: BlockArrival[]; +} + +const METRIC_OPTIONS = [ + { value: 'mean' as CpuMetric, label: 'Mean' }, + { value: 'min' as CpuMetric, label: 'Min' }, + { value: 'max' as CpuMetric, label: 'Max' }, +]; + +export function NodeResourcesPanel({ slot, blockPropagationData }: NodeResourcesPanelProps): JSX.Element { + const { data, isLoading, error } = useSlotNodeResources(slot); + const search = useSearch({ from: '/ethereum/slots/$slot' }); + const navigate = useNavigate(); + const [showRefNodeInfo, setShowRefNodeInfo] = useState(false); + + // URL-backed state + const referenceNodesOnly = search.refNodes ?? false; + const selectedNode = search.node ?? null; + const metric: CpuMetric = search.metric ?? 'mean'; + + const setReferenceNodesOnly = useCallback( + (value: boolean) => { + navigate({ + to: '/ethereum/slots/$slot', + params: { slot: String(slot) }, + search: prev => ({ ...prev, refNodes: value || undefined }), + replace: true, + }); + }, + [navigate, slot] + ); + + const setSelectedNode = useCallback( + (value: string | null) => { + navigate({ + to: '/ethereum/slots/$slot', + params: { slot: String(slot) }, + search: prev => ({ ...prev, node: value ?? undefined }), + replace: true, + }); + }, + [navigate, slot] + ); + + const setMetric = useCallback( + (value: CpuMetric) => { + navigate({ + to: '/ethereum/slots/$slot', + params: { slot: String(slot) }, + search: prev => ({ ...prev, metric: value === 'mean' ? undefined : value }), + replace: true, + }); + }, + [navigate, slot] + ); + + // Filter data based on reference nodes toggle + const filteredData = useMemo(() => { + if (!data) return []; + if (!referenceNodesOnly) return data; + return data.filter( + d => d.node_class === 'eip7870' || extractClusterFromNodeName(d.meta_client_name ?? '') !== null + ); + }, [data, referenceNodesOnly]); + + // Get unique node names from filtered data + const nodeNames = useMemo(() => { + const names = new Set(filteredData.map(d => d.meta_client_name).filter(Boolean) as string[]); + return Array.from(names).sort(); + }, [filteredData]); + + // Build node → {cl, el} client info map from the data + const nodeClientInfo = useMemo(() => { + const info = new Map(); + for (const d of filteredData) { + const name = d.meta_client_name; + const clientType = d.client_type?.toLowerCase() ?? ''; + if (!name) continue; + + const existing = info.get(name) ?? { cl: '', el: '' }; + if (CL_CLIENTS.has(clientType) && !existing.cl) { + existing.cl = clientType; + } else if (EL_CLIENTS.has(clientType) && !existing.el) { + existing.el = clientType; + } + info.set(name, existing); + } + return info; + }, [filteredData]); + + // Reset selected node if it's no longer in the filtered list + const effectiveSelectedNode = selectedNode && nodeNames.includes(selectedNode) ? selectedNode : null; + + if (isLoading) { + return ( + +
+

Node Resources

+

CPU utilization from observoor eBPF agent

+
+
+
+
+
+ + ); + } + + if (error) { + return ( + +
+

Failed to load node resource data: {error.message}

+
+
+ ); + } + + if (!data || data.length === 0) { + return ( + +
+

No node resource data available for this slot

+
+
+ ); + } + + return ( +
+ {/* Controls */} + +
+
+

Node Resources

+

CPU utilization across {nodeNames.length} nodes during this slot

+
+
+ + {!effectiveSelectedNode && ( + + )} +
+ + +
+
+
+
+ + {/* Chart */} + + + setShowRefNodeInfo(false)} /> +
+ ); +} diff --git a/src/pages/ethereum/slots/components/NodeResources/NodeSelector.tsx b/src/pages/ethereum/slots/components/NodeResources/NodeSelector.tsx new file mode 100644 index 000000000..638a08229 --- /dev/null +++ b/src/pages/ethereum/slots/components/NodeResources/NodeSelector.tsx @@ -0,0 +1,45 @@ +import type { JSX } from 'react'; +import { SelectMenu } from '@/components/Forms/SelectMenu'; +import { ClientLogo } from '@/components/Ethereum/ClientLogo'; + +export interface NodeClientInfo { + cl: string; + el: string; +} + +interface NodeSelectorProps { + nodes: string[]; + selectedNode: string | null; + onChange: (node: string | null) => void; + nodeClientInfo: Map; +} + +export function NodeSelector({ nodes, selectedNode, onChange, nodeClientInfo }: NodeSelectorProps): JSX.Element { + const options = [ + { value: '__all__', label: `All nodes (${nodes.length})` }, + ...nodes.map(node => { + const info = nodeClientInfo.get(node); + const shortName = node.split('/').pop() ?? node; + return { + value: node, + label: shortName, + icon: + info?.cl || info?.el ? ( + + {info.cl && } + {info.el && } + + ) : undefined, + }; + }), + ]; + + return ( + onChange(value === '__all__' ? null : value)} + options={options} + expandToFit + /> + ); +} diff --git a/src/pages/ethereum/slots/components/NodeResources/index.ts b/src/pages/ethereum/slots/components/NodeResources/index.ts new file mode 100644 index 000000000..c70f19632 --- /dev/null +++ b/src/pages/ethereum/slots/components/NodeResources/index.ts @@ -0,0 +1 @@ +export { NodeResourcesPanel } from './NodeResourcesPanel'; diff --git a/src/pages/ethereum/slots/hooks/useSlotNodeResources/index.ts b/src/pages/ethereum/slots/hooks/useSlotNodeResources/index.ts new file mode 100644 index 000000000..61141fa54 --- /dev/null +++ b/src/pages/ethereum/slots/hooks/useSlotNodeResources/index.ts @@ -0,0 +1,2 @@ +export { useSlotNodeResources } from './useSlotNodeResources'; +export type { UseSlotNodeResourcesResult } from './useSlotNodeResources'; diff --git a/src/pages/ethereum/slots/hooks/useSlotNodeResources/useSlotNodeResources.ts b/src/pages/ethereum/slots/hooks/useSlotNodeResources/useSlotNodeResources.ts new file mode 100644 index 000000000..d810d84dc --- /dev/null +++ b/src/pages/ethereum/slots/hooks/useSlotNodeResources/useSlotNodeResources.ts @@ -0,0 +1,38 @@ +import { useQuery } from '@tanstack/react-query'; +import { fctNodeCpuUtilizationServiceListOptions } from '@/api/@tanstack/react-query.gen'; +import { useNetwork } from '@/hooks/useNetwork'; +import { slotToTimestamp } from '@/utils/beacon'; +import type { FctNodeCpuUtilization } from '@/api/types.gen'; + +/** cbt-api returns DateTime64(3) fields as microseconds */ +const SECONDS_TO_MICROSECONDS = 1_000_000; + +export interface UseSlotNodeResourcesResult { + data: FctNodeCpuUtilization[] | null; + isLoading: boolean; + error: Error | null; +} + +export function useSlotNodeResources(slot: number): UseSlotNodeResourcesResult { + const { currentNetwork } = useNetwork(); + const slotTimestamp = currentNetwork ? slotToTimestamp(slot, currentNetwork.genesis_time) : 0; + const slotTimestampUs = slotTimestamp * SECONDS_TO_MICROSECONDS; + + const { data, isLoading, error } = useQuery({ + ...fctNodeCpuUtilizationServiceListOptions({ + query: { + wallclock_slot_start_date_time_eq: slotTimestampUs, + page_size: 10000, + }, + }), + enabled: !!currentNetwork && slotTimestamp > 0, + }); + + const cpuData = data?.fct_node_cpu_utilization ?? null; + + return { + data: cpuData, + isLoading, + error: error as Error | null, + }; +} diff --git a/src/routes/ethereum/slots/$slot.tsx b/src/routes/ethereum/slots/$slot.tsx index 25b5bcc5d..455442cdd 100644 --- a/src/routes/ethereum/slots/$slot.tsx +++ b/src/routes/ethereum/slots/$slot.tsx @@ -4,9 +4,12 @@ import { DetailPage } from '@/pages/ethereum/slots'; const slotSearchSchema = z.object({ tab: z - .enum(['overview', 'timeline', 'block', 'attestations', 'propagation', 'blobs', 'execution', 'mev']) + .enum(['overview', 'timeline', 'block', 'attestations', 'propagation', 'blobs', 'execution', 'mev', 'resources']) .default('overview'), contributor: z.string().optional(), + node: z.string().optional(), + metric: z.enum(['mean', 'min', 'max']).optional(), + refNodes: z.coerce.boolean().optional(), }); export const Route = createFileRoute('/ethereum/slots/$slot')({ From f749816f3f52e6dfff9c66559f1c045ca42414bd Mon Sep 17 00:00:00 2001 From: Sam Calder-Mason Date: Thu, 12 Feb 2026 14:34:08 +1000 Subject: [PATCH 02/15] refactor: redesign CPU chart with min-max bands and clearer labels Replace 8 separate line series with shaded min-max bands and clean mean lines. Legend drops from 8 items to 2-4. "sys" terminology replaced with "% of all cores". Slot number added to subtitle. Peak core series hidden by default (toggle-able in legend). --- .../NodeResources/CpuUtilizationChart.tsx | 240 +++++++++++------- .../NodeResources/NodeResourcesPanel.tsx | 8 +- 2 files changed, 151 insertions(+), 97 deletions(-) diff --git a/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx b/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx index ec6a5d9be..2ef69f9a1 100644 --- a/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx @@ -22,19 +22,14 @@ function usToSeconds(us: number): number { return us / 1_000_000; } -/** Get the normalized metric value (0-100% of total system) from a data point */ -function getMetricValue(d: FctNodeCpuUtilization, metric: CpuMetric): number { - const cores = d.system_cores ?? 1; +function capitalize(s: string): string { + return s.charAt(0).toUpperCase() + s.slice(1); +} + +/** Normalize a metric value to % of total system CPU */ +function normalizeToSystem(value: number, cores: number): number { const divisor = cores > 0 ? cores : 1; - switch (metric) { - case 'min': - return (d.min_core_pct ?? 0) / divisor; - case 'max': - return (d.max_core_pct ?? 0) / divisor; - case 'mean': - default: - return (d.mean_core_pct ?? 0) / divisor; - } + return value / divisor; } const METRIC_LABELS: Record = { @@ -48,18 +43,32 @@ interface BlockArrival { node_id: string; } +/** Aggregated bucket data for a single time window */ +interface BucketAgg { + meanVals: number[]; + minVals: number[]; + maxVals: number[]; + coreVals: number[]; +} + interface CpuUtilizationChartProps { data: FctNodeCpuUtilization[]; selectedNode: string | null; blockPropagationData: BlockArrival[]; metric: CpuMetric; + slot: number; } +const BUCKET_SIZE = 0.25; +const toBucket = (offsetSec: number): number => Math.round(offsetSec / BUCKET_SIZE) * BUCKET_SIZE; +const avg = (arr: number[]): number => arr.reduce((s, v) => s + v, 0) / arr.length; + export function CpuUtilizationChart({ data, selectedNode, blockPropagationData, metric, + slot, }: CpuUtilizationChartProps): JSX.Element { const { CHART_CATEGORICAL_COLORS } = getDataVizColors(); @@ -68,56 +77,68 @@ export function CpuUtilizationChart({ return { series: [] as SeriesData[], markLines: [] as MarkLineConfig[], clClient: '', elClient: '' }; } - // Derive slot start time from data (microseconds) const slotStartUs = Math.min(...data.map(d => d.wallclock_slot_start_date_time ?? 0).filter(v => v > 0)); - const chartSeries: SeriesData[] = []; let resolvedClClient = ''; let resolvedElClient = ''; - // Bucket size for time aggregation (seconds) - const BUCKET_SIZE = 0.25; - const toBucket = (offsetSec: number): number => Math.round(offsetSec / BUCKET_SIZE) * BUCKET_SIZE; - - const buildLine = ( - items: FctNodeCpuUtilization[], - label: string, - color: string, - getValue: CpuMetric | ((d: FctNodeCpuUtilization) => number), - opts?: { - lineWidth?: number; - showArea?: boolean; - areaOpacity?: number; - lineStyle?: 'solid' | 'dashed' | 'dotted'; - } - ): void => { - const extractValue = - typeof getValue === 'function' ? getValue : (d: FctNodeCpuUtilization) => getMetricValue(d, getValue); - - const byBucket = new Map(); - items.forEach(d => { + /** Bucket data points by time offset, collecting all metric values per bucket */ + const bucketData = (items: FctNodeCpuUtilization[]): Map => { + const buckets = new Map(); + for (const d of items) { const offset = usToSeconds((d.window_start ?? 0) - slotStartUs); const bucket = toBucket(offset); - if (bucket < 0 || bucket > 12) return; - if (!byBucket.has(bucket)) byBucket.set(bucket, []); - byBucket.get(bucket)!.push(extractValue(d)); - }); + if (bucket < 0 || bucket > 12) continue; - const points = Array.from(byBucket.entries()) - .sort(([a], [b]) => a - b) - .map(([offset, values]) => [offset, values.reduce((s, v) => s + v, 0) / values.length] as [number, number]); - - if (points.length > 0) { - chartSeries.push({ - name: label, - data: points, - color, - lineWidth: opts?.lineWidth ?? 2, - showArea: opts?.showArea ?? true, - areaOpacity: opts?.areaOpacity ?? 0.08, - lineStyle: opts?.lineStyle, - }); + if (!buckets.has(bucket)) { + buckets.set(bucket, { meanVals: [], minVals: [], maxVals: [], coreVals: [] }); + } + const b = buckets.get(bucket)!; + const cores = d.system_cores ?? 1; + b.meanVals.push(normalizeToSystem(d.mean_core_pct ?? 0, cores)); + b.minVals.push(normalizeToSystem(d.min_core_pct ?? 0, cores)); + b.maxVals.push(normalizeToSystem(d.max_core_pct ?? 0, cores)); + b.coreVals.push(Math.min(d.max_core_pct ?? 0, 100)); } + return buckets; + }; + + /** Convert bucketed data to sorted [time, value] points */ + const toPoints = (buckets: Map, extract: (b: BucketAgg) => number[]): [number, number][] => + Array.from(buckets.entries()) + .sort(([a], [b]) => a - b) + .map(([t, b]) => [t, avg(extract(b))] as [number, number]); + + /** Add a band (min-max range) as two stacked series */ + const addBand = (buckets: Map, stackId: string, color: string): void => { + const sorted = Array.from(buckets.entries()).sort(([a], [b]) => a - b); + const basePoints = sorted.map(([t, b]) => [t, avg(b.minVals)] as [number, number]); + const widthPoints = sorted.map(([t, b]) => { + const lo = avg(b.minVals); + const hi = avg(b.maxVals); + return [t, Math.max(0, hi - lo)] as [number, number]; + }); + + chartSeries.push({ + name: `_${stackId}_base`, + data: basePoints, + stack: stackId, + showArea: true, + areaOpacity: 0, + lineWidth: 0, + color, + visible: false, + }); + chartSeries.push({ + name: `_${stackId}_width`, + data: widthPoints, + stack: stackId, + showArea: true, + areaOpacity: 0.12, + lineWidth: 0, + color, + visible: false, + }); }; if (selectedNode) { @@ -128,57 +149,90 @@ export function CpuUtilizationChart({ resolvedClClient = clData[0]?.client_type ?? ''; resolvedElClient = elData[0]?.client_type ?? ''; - const clLabel = resolvedClClient || 'CL'; - const elLabel = resolvedElClient || 'EL'; + const clLabel = capitalize(resolvedClClient || 'CL'); + const elLabel = capitalize(resolvedElClient || 'EL'); const clColor = CHART_CATEGORICAL_COLORS[0]; const elColor = CHART_CATEGORICAL_COLORS[1]; - const coreExtract = (d: FctNodeCpuUtilization) => Math.min(d.max_core_pct ?? 0, 100); + const clBuckets = bucketData(clData); + const elBuckets = bucketData(elData); - // CL system utilization: mean (solid), min (dotted), max (dashed) - buildLine(clData, `${clLabel} sys mean`, clColor, 'mean', { lineWidth: 2, showArea: true, areaOpacity: 0.06 }); - buildLine(clData, `${clLabel} sys min`, clColor, 'min', { - lineWidth: 1.5, - showArea: false, - lineStyle: 'dotted', - }); - buildLine(clData, `${clLabel} sys max`, clColor, 'max', { - lineWidth: 1.5, + // CL: min-max band, then mean line on top + addBand(clBuckets, 'cl_range', clColor); + chartSeries.push({ + name: `${clLabel}`, + data: toPoints(clBuckets, b => b.meanVals), + color: clColor, + lineWidth: 2, showArea: false, - lineStyle: 'dashed', }); - // EL system utilization: mean (solid), min (dotted), max (dashed) - buildLine(elData, `${elLabel} sys mean`, elColor, 'mean', { lineWidth: 2, showArea: true, areaOpacity: 0.06 }); - buildLine(elData, `${elLabel} sys min`, elColor, 'min', { - lineWidth: 1.5, + // EL: min-max band, then mean line on top + addBand(elBuckets, 'el_range', elColor); + chartSeries.push({ + name: `${elLabel}`, + data: toPoints(elBuckets, b => b.meanVals), + color: elColor, + lineWidth: 2, showArea: false, - lineStyle: 'dotted', - }); - buildLine(elData, `${elLabel} sys max`, elColor, 'max', { - lineWidth: 1.5, - showArea: false, - lineStyle: 'dashed', }); - // Hottest single core per client (raw, not divided by system_cores) - const singleCoreColor = CHART_CATEGORICAL_COLORS[2] ?? '#e5a00d'; - buildLine(clData, `${clLabel} hottest core`, singleCoreColor, coreExtract, { + // Busiest single core per client + chartSeries.push({ + name: `${clLabel} peak core`, + data: toPoints(clBuckets, b => b.coreVals), + color: clColor, lineWidth: 1.5, - showArea: false, lineStyle: 'dashed', + showArea: false, + initiallyVisible: false, }); - buildLine(elData, `${elLabel} hottest core`, singleCoreColor, coreExtract, { + chartSeries.push({ + name: `${elLabel} peak core`, + data: toPoints(elBuckets, b => b.coreVals), + color: elColor, lineWidth: 1.5, + lineStyle: 'dashed', showArea: false, - lineStyle: 'dotted', + initiallyVisible: false, }); } else { + // Aggregate view: CL/EL with selected metric const clData = data.filter(d => getClientLayer(d.client_type ?? '') === 'CL'); const elData = data.filter(d => getClientLayer(d.client_type ?? '') === 'EL'); - buildLine(clData, 'Consensus Layer', CHART_CATEGORICAL_COLORS[0], metric); - buildLine(elData, 'Execution Layer', CHART_CATEGORICAL_COLORS[1], metric); + const metricExtract = (b: BucketAgg): number[] => { + switch (metric) { + case 'min': + return b.minVals; + case 'max': + return b.maxVals; + case 'mean': + default: + return b.meanVals; + } + }; + + const clBuckets = bucketData(clData); + const elBuckets = bucketData(elData); + + addBand(clBuckets, 'cl_range', CHART_CATEGORICAL_COLORS[0]); + chartSeries.push({ + name: 'Consensus Layer', + data: toPoints(clBuckets, metricExtract), + color: CHART_CATEGORICAL_COLORS[0], + lineWidth: 2, + showArea: false, + }); + + addBand(elBuckets, 'el_range', CHART_CATEGORICAL_COLORS[1]); + chartSeries.push({ + name: 'Execution Layer', + data: toPoints(elBuckets, metricExtract), + color: CHART_CATEGORICAL_COLORS[1], + lineWidth: 2, + showArea: false, + }); } // Block arrival markLines @@ -235,8 +289,8 @@ export function CpuUtilizationChart({ const shortNodeName = selectedNode?.split('/').pop() ?? ''; const subtitle = selectedNode - ? `${shortNodeName} · sys% = total system, hottest core = single core peak` - : `${METRIC_LABELS[metric]} across ${nodeCount} nodes · % of total system`; + ? `Slot ${slot} · ${shortNodeName} · shaded = min/max range, dashed = busiest core` + : `Slot ${slot} · ${METRIC_LABELS[metric]} across ${nodeCount} nodes · % of all CPU cores`; const headerActions = selectedNode && (clClient || elClient) ? ( @@ -273,7 +327,7 @@ export function CpuUtilizationChart({ formatter: (v: number | string) => `${v}s`, }} yAxis={{ - name: 'CPU %', + name: '% of all cores', min: 0, formatter: (v: number) => `${v.toFixed(1)}%`, }} @@ -282,20 +336,24 @@ export function CpuUtilizationChart({ legendPosition="bottom" markLines={markLines} syncGroup="slot-time" - valueDecimals={1} tooltipFormatter={(params: unknown) => { const items = Array.isArray(params) ? params : [params]; if (items.length === 0) return ''; + // Filter out hidden band series from tooltip + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const visible = items.filter((p: any) => !String(p.seriesName).startsWith('_')); + if (visible.length === 0) return ''; + // eslint-disable-next-line @typescript-eslint/no-explicit-any - const first = items[0] as any; + const first = visible[0] as any; const xVal = Array.isArray(first.value) ? first.value[0] : first.axisValue; - const timeStr = typeof xVal === 'number' ? `${xVal.toFixed(3)}s` : `${xVal}s`; + const timeStr = typeof xVal === 'number' ? `${xVal.toFixed(2)}s` : `${xVal}s`; let html = `
`; html += `
${timeStr}
`; - for (const item of items) { + for (const item of visible) { // eslint-disable-next-line @typescript-eslint/no-explicit-any const p = item as any; const val = Array.isArray(p.value) ? p.value[1] : p.value; diff --git a/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx b/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx index 95311373d..fa9ac2328 100644 --- a/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx @@ -167,12 +167,7 @@ export function NodeResourcesPanel({ slot, blockPropagationData }: NodeResources nodeClientInfo={nodeClientInfo} /> {!effectiveSelectedNode && ( - + )}
+ + {/* Annotation toggles */} + {availableAnnotations.length > 0 && ( +
+ Annotations: + {availableAnnotations.map(opt => ( + + ))} +
+ )} {/* Chart */} setShowRefNodeInfo(false)} /> diff --git a/src/pages/ethereum/slots/components/NodeResources/types.ts b/src/pages/ethereum/slots/components/NodeResources/types.ts new file mode 100644 index 000000000..b76494bf1 --- /dev/null +++ b/src/pages/ethereum/slots/components/NodeResources/types.ts @@ -0,0 +1,20 @@ +export type AnnotationType = 'block' | 'head' | 'execution' | 'data_columns'; + +export interface AnnotationEvent { + type: AnnotationType; + /** Time in milliseconds from slot start */ + timeMs: number; + /** Optional end time for range annotations */ + endMs?: number; + /** Optional label suffix */ + label?: string; + /** Node name this event belongs to (for filtering) */ + nodeName?: string; +} + +export const ANNOTATION_OPTIONS: { value: AnnotationType; label: string; description: string }[] = [ + { value: 'block', label: 'Block Arrival', description: 'When block gossip was received' }, + { value: 'head', label: 'Head Update', description: 'When chain head was updated' }, + { value: 'execution', label: 'Execution', description: 'Engine newPayload call duration' }, + { value: 'data_columns', label: 'Data Columns', description: 'First to last data column received' }, +]; From 1013d7153d4c774f6c9432bbd551ea9ca1484139 Mon Sep 17 00:00:00 2001 From: Sam Calder-Mason Date: Thu, 12 Feb 2026 15:45:04 +1000 Subject: [PATCH 04/15] feat: add markArea annotations, slot phase boundaries, and UX improvements - Add markArea support to MultiLineChart (colored regions on chart) - Add slot phase boundary markLines (Block/Attestations/Aggregations) - Move metric dropdown into chart PopoutCard header - Change aggregate annotation ranges from p25-p75 to min-p95 - Fix double-toggle on annotation/7870 checkboxes (pointer-events-none) - Fix scroll-to-top on control changes (resetScroll: false) - Extract shared CL/EL client sets to utils/ethereum.ts - Update subtitle to link to Observoor repo --- src/components/Charts/MultiLine/MultiLine.tsx | 92 +++++--- .../Charts/MultiLine/MultiLine.types.ts | 33 +++ src/components/Charts/MultiLine/index.ts | 1 + .../NodeResources/CpuUtilizationChart.tsx | 209 ++++++++++++------ .../NodeResources/NodeResourcesPanel.tsx | 190 +++++++--------- .../slots/components/NodeResources/types.ts | 15 +- src/utils/ethereum.ts | 17 ++ 7 files changed, 345 insertions(+), 212 deletions(-) diff --git a/src/components/Charts/MultiLine/MultiLine.tsx b/src/components/Charts/MultiLine/MultiLine.tsx index e6c598b82..88f60025f 100644 --- a/src/components/Charts/MultiLine/MultiLine.tsx +++ b/src/components/Charts/MultiLine/MultiLine.tsx @@ -12,6 +12,7 @@ import { DataZoomComponent, LegendComponent, MarkLineComponent, + MarkAreaComponent, } from 'echarts/components'; import { CanvasRenderer } from 'echarts/renderers'; import { hexToRgba, formatSmartDecimal, getDataVizColors, resolveCssColorToHex } from '@/utils'; @@ -30,6 +31,7 @@ echarts.use([ DataZoomComponent, LegendComponent, MarkLineComponent, + MarkAreaComponent, CanvasRenderer, ]); @@ -95,6 +97,7 @@ export function MultiLineChart({ notMerge = true, onSeriesClick, markLines, + markAreas, }: MultiLineChartProps): React.JSX.Element { // Store ref to the ReactEChartsCore wrapper (not the instance) for click handling const chartWrapperRef = useRef(null); @@ -580,41 +583,73 @@ export function MultiLineChart({ return baseConfig; }); - // Add annotation series for markLines if provided + // Add annotation series for markLines/markAreas if provided + const hasMarkLines = markLines && markLines.length > 0; + const hasMarkAreas = markAreas && markAreas.length > 0; const annotationSeries = - markLines && markLines.length > 0 + hasMarkLines || hasMarkAreas ? [ { name: '__annotations__', type: 'line' as const, - data: [], // Empty data - this series is only for markLine + data: [], // Empty data - this series is only for annotations silent: true, // Don't trigger events legendHoverLink: false, - markLine: { - silent: true, - symbol: 'none', - animation: false, - data: markLines.map(ml => ({ - xAxis: ml.xValue, - label: { - show: !!ml.label, - formatter: ml.label ?? '', - position: ml.labelPosition ?? 'end', - rotate: -90, - align: 'left', - offset: [0, -2], - color: hexToRgba(ml.color ?? themeColors.muted, 0.7), - fontSize: 11, - backgroundColor: 'transparent', - padding: [2, 4], - }, - lineStyle: { - color: ml.color ?? themeColors.muted, - type: (ml.lineStyle ?? 'dashed') as 'solid' | 'dashed' | 'dotted', - width: ml.lineWidth ?? 1, - }, - })), - }, + ...(hasMarkLines + ? { + markLine: { + silent: true, + symbol: 'none', + animation: false, + data: markLines!.map(ml => ({ + xAxis: ml.xValue, + label: { + show: !!ml.label, + formatter: ml.label ?? '', + position: ml.labelPosition ?? 'end', + rotate: -90, + align: 'left', + offset: ml.distance ?? [0, -2], + color: hexToRgba(ml.color ?? themeColors.muted, 0.7), + fontSize: 11, + backgroundColor: 'transparent', + padding: [2, 4], + }, + lineStyle: { + color: ml.color ?? themeColors.muted, + type: (ml.lineStyle ?? 'dashed') as 'solid' | 'dashed' | 'dotted', + width: ml.lineWidth ?? 1, + }, + })), + }, + } + : {}), + ...(hasMarkAreas + ? { + markArea: { + silent: true, + animation: false, + data: markAreas!.map(ma => [ + { + xAxis: ma.xStart, + itemStyle: { + color: hexToRgba(ma.color ?? themeColors.muted, ma.opacity ?? 0.15), + }, + label: { + show: !!ma.label, + formatter: ma.label ?? '', + position: 'insideTop' as const, + color: hexToRgba(ma.color ?? themeColors.muted, 0.8), + fontSize: 10, + }, + }, + { + xAxis: ma.xEnd, + }, + ]), + }, + } + : {}), }, ] : []; @@ -861,6 +896,7 @@ export function MultiLineChart({ showLegend, legendPosition, markLines, + markAreas, ]); const chartContent = ( diff --git a/src/components/Charts/MultiLine/MultiLine.types.ts b/src/components/Charts/MultiLine/MultiLine.types.ts index a97bff90e..de14ab980 100644 --- a/src/components/Charts/MultiLine/MultiLine.types.ts +++ b/src/components/Charts/MultiLine/MultiLine.types.ts @@ -257,6 +257,34 @@ export interface MarkLineConfig { distance?: [number, number]; } +/** + * Configuration for a vertical annotation area (markArea) + * Renders a semi-transparent colored rectangle spanning the full y-axis + */ +export interface MarkAreaConfig { + /** + * Start x-axis value + */ + xStart: number | string; + /** + * End x-axis value + */ + xEnd: number | string; + /** + * Area color (hex or rgb) + */ + color?: string; + /** + * Area opacity (0-1) + * @default 0.15 + */ + opacity?: number; + /** + * Label to display inside the area + */ + label?: string; +} + /** * MultiLineChart component props */ @@ -410,4 +438,9 @@ export interface MultiLineChartProps { * Useful for marking important events like resurrections or thresholds */ markLines?: MarkLineConfig[]; + /** + * Vertical annotation areas to display on the chart + * Renders semi-transparent colored rectangles spanning the full y-axis + */ + markAreas?: MarkAreaConfig[]; } diff --git a/src/components/Charts/MultiLine/index.ts b/src/components/Charts/MultiLine/index.ts index 21e937e10..c97c7b739 100644 --- a/src/components/Charts/MultiLine/index.ts +++ b/src/components/Charts/MultiLine/index.ts @@ -1,6 +1,7 @@ export { MultiLineChart } from './MultiLine'; export type { EnrichedDataPoint, + MarkAreaConfig, MarkLineConfig, MultiLineChartProps, SeriesData, diff --git a/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx b/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx index ab8834700..11854ded3 100644 --- a/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx @@ -1,22 +1,13 @@ import { type JSX, useMemo } from 'react'; import { PopoutCard } from '@/components/Layout/PopoutCard'; import { MultiLineChart } from '@/components/Charts/MultiLine'; -import type { SeriesData, MarkLineConfig } from '@/components/Charts/MultiLine/MultiLine.types'; -import { getDataVizColors } from '@/utils'; +import type { SeriesData, MarkAreaConfig, MarkLineConfig } from '@/components/Charts/MultiLine/MultiLine.types'; +import { getDataVizColors, getClientLayer } from '@/utils'; +import { DEFAULT_BEACON_SLOT_PHASES } from '@/utils/beacon'; import { ClientLogo } from '@/components/Ethereum/ClientLogo'; +import { SelectMenu } from '@/components/Forms/SelectMenu'; import type { FctNodeCpuUtilization } from '@/api/types.gen'; -import type { CpuMetric } from './NodeResourcesPanel'; -import type { AnnotationType, AnnotationEvent } from './types'; - -const CL_CLIENTS = new Set(['lighthouse', 'lodestar', 'nimbus', 'prysm', 'teku', 'grandine']); -const EL_CLIENTS = new Set(['besu', 'erigon', 'geth', 'nethermind', 'reth']); - -function getClientLayer(clientType: string): 'CL' | 'EL' | null { - const lower = clientType.toLowerCase(); - if (CL_CLIENTS.has(lower)) return 'CL'; - if (EL_CLIENTS.has(lower)) return 'EL'; - return null; -} +import { ANNOTATION_COLORS, type CpuMetric, type AnnotationType, type AnnotationEvent } from './types'; function usToSeconds(us: number): number { return us / 1_000_000; @@ -37,19 +28,25 @@ const METRIC_LABELS: Record = { max: 'Max', }; -const ANNOTATION_COLORS: Record = { - block: '#f59e0b', - head: '#8b5cf6', - execution: '#ef4444', - data_columns: '#10b981', -}; +const METRIC_OPTIONS = [ + { value: 'mean' as CpuMetric, label: 'Mean' }, + { value: 'min' as CpuMetric, label: 'Min' }, + { value: 'max' as CpuMetric, label: 'Max' }, +]; -const ANNOTATION_LABELS: Record = { - block: 'Block', - head: 'Head', - execution: 'Exec', - data_columns: 'DA', -}; +/** Minimum width in seconds for point-event areas so they're visible */ +const MIN_AREA_WIDTH_SEC = 0.08; + +/** Match a CPU node name to propagation node_id (fuzzy matching) */ +function nodeMatches(cpuNodeName: string, propNodeId: string): boolean { + const short = cpuNodeName.split('/').pop() ?? cpuNodeName; + return propNodeId === short || propNodeId === cpuNodeName || short.includes(propNodeId) || propNodeId.includes(short); +} + +function percentile(sorted: number[], p: number): number { + const idx = Math.floor(sorted.length * p); + return sorted[Math.min(idx, sorted.length - 1)]; +} interface BucketAgg { meanVals: number[]; @@ -62,6 +59,7 @@ interface CpuUtilizationChartProps { data: FctNodeCpuUtilization[]; selectedNode: string | null; metric: CpuMetric; + onMetricChange: (metric: CpuMetric) => void; slot: number; annotations: AnnotationEvent[]; enabledAnnotations: Set; @@ -75,15 +73,16 @@ export function CpuUtilizationChart({ data, selectedNode, metric, + onMetricChange, slot, annotations, enabledAnnotations, }: CpuUtilizationChartProps): JSX.Element { const { CHART_CATEGORICAL_COLORS } = getDataVizColors(); - const { series, markLines, clClient, elClient } = useMemo(() => { + const { series, clClient, elClient } = useMemo(() => { if (data.length === 0) { - return { series: [] as SeriesData[], markLines: [] as MarkLineConfig[], clClient: '', elClient: '' }; + return { series: [] as SeriesData[], clClient: '', elClient: '' }; } const slotStartUs = Math.min(...data.map(d => d.wallclock_slot_start_date_time ?? 0).filter(v => v > 0)); @@ -144,7 +143,6 @@ export function CpuUtilizationChart({ const clBuckets = bucketData(clData); const elBuckets = bucketData(elData); - // CL mean line with gradient fill chartSeries.push({ name: clLabel, data: toPoints(clBuckets, b => b.meanVals), @@ -154,7 +152,6 @@ export function CpuUtilizationChart({ areaOpacity: 0.08, }); - // EL mean line with gradient fill chartSeries.push({ name: elLabel, data: toPoints(elBuckets, b => b.meanVals), @@ -164,7 +161,6 @@ export function CpuUtilizationChart({ areaOpacity: 0.08, }); - // Peak core (hidden by default) chartSeries.push({ name: `${clLabel} peak core`, data: toPoints(clBuckets, b => b.coreVals), @@ -209,51 +205,118 @@ export function CpuUtilizationChart({ }); } - // Build annotation markLines - const chartMarkLines: MarkLineConfig[] = []; - - for (const anno of annotations) { - if (!enabledAnnotations.has(anno.type)) continue; + return { series: chartSeries, clClient: resolvedClClient, elClient: resolvedElClient }; + }, [data, selectedNode, metric, CHART_CATEGORICAL_COLORS]); - const timeSec = anno.timeMs / 1000; - if (timeSec < 0 || timeSec > 12) continue; + // Convert annotations to markAreas (chart handles node matching + aggregation) + const markAreas = useMemo((): MarkAreaConfig[] => { + const areas: MarkAreaConfig[] = []; - const color = ANNOTATION_COLORS[anno.type]; - const prefix = ANNOTATION_LABELS[anno.type]; - const label = anno.label ? `${prefix}: ${anno.label}` : prefix; - - if (anno.endMs != null) { - // Range annotation: show start and end markLines - const endSec = anno.endMs / 1000; - if (endSec >= 0 && endSec <= 12) { - chartMarkLines.push({ - xValue: timeSec, - label: `${label} start`, - color, - lineStyle: 'dashed', - lineWidth: 1, - }); - chartMarkLines.push({ - xValue: endSec, - label: `${label} end`, + if (selectedNode) { + // Single node: find matching events and render exact positions + for (const anno of annotations) { + if (!enabledAnnotations.has(anno.type)) continue; + if (!anno.nodeName || !nodeMatches(selectedNode, anno.nodeName)) continue; + + const startSec = anno.timeMs / 1000; + if (startSec < 0 || startSec > 12) continue; + const color = ANNOTATION_COLORS[anno.type]; + const hasRange = anno.endMs != null && Math.abs(anno.endMs - anno.timeMs) > 10; + + if (hasRange) { + const endSec = Math.min(anno.endMs! / 1000, 12); + areas.push({ xStart: startSec, xEnd: endSec, color, opacity: 0.12 }); + } else { + areas.push({ + xStart: startSec - MIN_AREA_WIDTH_SEC / 2, + xEnd: startSec + MIN_AREA_WIDTH_SEC / 2, color, - lineStyle: 'dashed', - lineWidth: 1, + opacity: 0.3, }); } - } else { - chartMarkLines.push({ - xValue: timeSec, - label, - color, - lineStyle: 'dashed', - lineWidth: 1, - }); } + } else { + // Aggregate: compute min–p95 range per annotation type + const byType = new Map(); + for (const anno of annotations) { + if (!enabledAnnotations.has(anno.type)) continue; + if (!byType.has(anno.type)) byType.set(anno.type, []); + byType.get(anno.type)!.push(anno); + } + + for (const [type, events] of byType) { + const color = ANNOTATION_COLORS[type]; + const hasRanges = events.some(e => e.endMs != null); + + if (hasRanges) { + // Range events (execution, data_columns): min of starts → p95 of ends + const starts = events.map(e => e.timeMs).sort((a, b) => a - b); + const ends = events.map(e => e.endMs ?? e.timeMs).sort((a, b) => a - b); + const startSec = starts[0] / 1000; + const endSec = percentile(ends, 0.95) / 1000; + if (startSec >= 0 && startSec <= 12) { + areas.push({ + xStart: Math.max(0, startSec), + xEnd: Math.min(12, endSec), + color, + opacity: 0.1, + }); + } + } else { + // Point events (block, head): min–p95 spread as area + const times = events.map(e => e.timeMs).sort((a, b) => a - b); + const minSec = times[0] / 1000; + const p95Sec = percentile(times, 0.95) / 1000; + if (minSec >= 0 && p95Sec <= 12) { + const width = p95Sec - minSec; + if (width < MIN_AREA_WIDTH_SEC) { + // Very tight spread: render as thin band at median + const medSec = percentile(times, 0.5) / 1000; + areas.push({ + xStart: medSec - MIN_AREA_WIDTH_SEC / 2, + xEnd: medSec + MIN_AREA_WIDTH_SEC / 2, + color, + opacity: 0.25, + }); + } else { + areas.push({ xStart: minSec, xEnd: p95Sec, color, opacity: 0.1 }); + } + } + } + } + } + + return areas; + }, [annotations, enabledAnnotations, selectedNode]); + + // Slot phase boundary markLines (e.g. attestation deadline at 4s, aggregation at 8s) + // Colors match the live slot view: cyan (block), green (attestation), amber (aggregation) + const PHASE_BOUNDARY_COLORS = ['#22d3ee', '#22c55e', '#f59e0b']; + + const markLines = useMemo((): MarkLineConfig[] => { + if (!enabledAnnotations.has('slot_phases')) return []; + + const lines: MarkLineConfig[] = []; + let cumulativeSec = 0; + + for (let i = 0; i < DEFAULT_BEACON_SLOT_PHASES.length - 1; i++) { + cumulativeSec += DEFAULT_BEACON_SLOT_PHASES[i].duration / 1000; + const nextPhase = DEFAULT_BEACON_SLOT_PHASES[i + 1]; + const color = PHASE_BOUNDARY_COLORS[i + 1] ?? '#6b7280'; + + lines.push({ + xValue: cumulativeSec, + label: nextPhase.label, + labelPosition: 'insideEndTop', + color, + lineStyle: 'dotted', + lineWidth: 1, + distance: [0, -8], + }); } - return { series: chartSeries, markLines: chartMarkLines, clClient: resolvedClClient, elClient: resolvedElClient }; - }, [data, selectedNode, metric, CHART_CATEGORICAL_COLORS, annotations, enabledAnnotations]); + return lines; + }, [enabledAnnotations]); const nodeCount = new Set(data.map(d => d.meta_client_name)).size; const shortNodeName = selectedNode?.split('/').pop() ?? ''; @@ -262,13 +325,16 @@ export function CpuUtilizationChart({ ? `Slot ${slot} · ${shortNodeName} · % of all CPU cores` : `Slot ${slot} · ${METRIC_LABELS[metric]} across ${nodeCount} nodes · % of all CPU cores`; - const headerActions = - selectedNode && (clClient || elClient) ? ( + const headerActions = selectedNode ? ( + clClient || elClient ? (
{clClient && } {elClient && }
- ) : undefined; + ) : undefined + ) : ( + + ); if (data.length === 0) { return ( @@ -305,6 +371,7 @@ export function CpuUtilizationChart({ showLegend legendPosition="bottom" markLines={markLines} + markAreas={markAreas} syncGroup="slot-time" tooltipFormatter={(params: unknown) => { const items = Array.isArray(params) ? params : [params]; diff --git a/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx b/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx index 49bbf6e93..147a778ff 100644 --- a/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx @@ -4,9 +4,9 @@ import { useQuery } from '@tanstack/react-query'; import { InformationCircleIcon } from '@heroicons/react/24/outline'; import { Card } from '@/components/Layout/Card'; import { Checkbox } from '@/components/Forms/Checkbox'; -import { SelectMenu } from '@/components/Forms/SelectMenu'; import { ReferenceNodesInfoDialog } from '@/pages/ethereum/execution/timings/components/ReferenceNodesInfoDialog'; import { extractClusterFromNodeName } from '@/constants/eip7870'; +import { CONSENSUS_CLIENTS, EXECUTION_CLIENTS_SET } from '@/utils/ethereum'; import { intEngineNewPayloadServiceListOptions } from '@/api/@tanstack/react-query.gen'; import type { FctBlockFirstSeenByNode, @@ -16,12 +16,15 @@ import type { import { useSlotNodeResources } from '../../hooks/useSlotNodeResources'; import { NodeSelector, type NodeClientInfo } from './NodeSelector'; import { CpuUtilizationChart } from './CpuUtilizationChart'; -import { ANNOTATION_OPTIONS, type AnnotationType, type AnnotationEvent } from './types'; +import { + ANNOTATION_OPTIONS, + ANNOTATION_COLORS, + type CpuMetric, + type AnnotationType, + type AnnotationEvent, +} from './types'; -export type CpuMetric = 'mean' | 'min' | 'max'; - -const CL_CLIENTS = new Set(['lighthouse', 'lodestar', 'nimbus', 'prysm', 'teku', 'grandine']); -const EL_CLIENTS = new Set(['besu', 'erigon', 'geth', 'nethermind', 'reth']); +export type { CpuMetric } from './types'; interface NodeResourcesPanelProps { slot: number; @@ -30,18 +33,6 @@ interface NodeResourcesPanelProps { dataColumnPropagation: FctBlockDataColumnSidecarFirstSeenByNode[]; } -const METRIC_OPTIONS = [ - { value: 'mean' as CpuMetric, label: 'Mean' }, - { value: 'min' as CpuMetric, label: 'Min' }, - { value: 'max' as CpuMetric, label: 'Max' }, -]; - -/** Match a CPU node name to propagation node_id (fuzzy matching) */ -function nodeMatches(cpuNodeName: string, propNodeId: string): boolean { - const short = cpuNodeName.split('/').pop() ?? cpuNodeName; - return propNodeId === short || propNodeId === cpuNodeName || short.includes(propNodeId) || propNodeId.includes(short); -} - export function NodeResourcesPanel({ slot, blockPropagation, @@ -53,7 +44,7 @@ export function NodeResourcesPanel({ const navigate = useNavigate(); const [showRefNodeInfo, setShowRefNodeInfo] = useState(false); const [enabledAnnotations, setEnabledAnnotations] = useState>( - () => new Set(['block', 'head', 'execution', 'data_columns']) + () => new Set(['slot_phases', 'block', 'head', 'execution', 'data_columns']) ); // Always fetch execution timing data so the toggle can show availability @@ -78,6 +69,7 @@ export function NodeResourcesPanel({ params: { slot: String(slot) }, search: prev => ({ ...prev, refNodes: value || undefined }), replace: true, + resetScroll: false, }); }, [navigate, slot] @@ -90,6 +82,7 @@ export function NodeResourcesPanel({ params: { slot: String(slot) }, search: prev => ({ ...prev, node: value ?? undefined }), replace: true, + resetScroll: false, }); }, [navigate, slot] @@ -102,6 +95,7 @@ export function NodeResourcesPanel({ params: { slot: String(slot) }, search: prev => ({ ...prev, metric: value === 'mean' ? undefined : value }), replace: true, + resetScroll: false, }); }, [navigate, slot] @@ -143,9 +137,9 @@ export function NodeResourcesPanel({ if (!name) continue; const existing = info.get(name) ?? { cl: '', el: '' }; - if (CL_CLIENTS.has(clientType) && !existing.cl) { + if (CONSENSUS_CLIENTS.has(clientType) && !existing.cl) { existing.cl = clientType; - } else if (EL_CLIENTS.has(clientType) && !existing.el) { + } else if (EXECUTION_CLIENTS_SET.has(clientType) && !existing.el) { existing.el = clientType; } info.set(name, existing); @@ -156,105 +150,66 @@ export function NodeResourcesPanel({ // Reset selected node if it's no longer in the filtered list const effectiveSelectedNode = selectedNode && nodeNames.includes(selectedNode) ? selectedNode : null; - // Build annotations from propagation data + // Build raw per-node annotation events (chart handles aggregation) const annotations = useMemo((): AnnotationEvent[] => { const events: AnnotationEvent[] = []; - if (effectiveSelectedNode) { - // Single node: show exact events for this node - for (const p of blockPropagation) { - if (p.node_id && nodeMatches(effectiveSelectedNode, p.node_id)) { - events.push({ type: 'block', timeMs: p.seen_slot_start_diff ?? 0, nodeName: effectiveSelectedNode }); - break; - } - } - - for (const p of headPropagation) { - if (p.node_id && nodeMatches(effectiveSelectedNode, p.node_id)) { - events.push({ type: 'head', timeMs: p.seen_slot_start_diff ?? 0, nodeName: effectiveSelectedNode }); - break; - } + for (const p of blockPropagation) { + if (p.node_id) { + events.push({ type: 'block', timeMs: p.seen_slot_start_diff ?? 0, nodeName: p.node_id }); } + } - // Execution timing for this node - const execItems = executionData?.int_engine_new_payload ?? []; - for (const e of execItems) { - if (e.meta_client_name && nodeMatches(effectiveSelectedNode, e.meta_client_name)) { - const slotStartMs = (e.slot_start_date_time ?? 0) * 1000; - const requestedMs = (e.requested_date_time ?? 0) / 1000; - const startMs = requestedMs - slotStartMs; - const durationMs = e.duration_ms ?? 0; - events.push({ - type: 'execution', - timeMs: startMs, - endMs: startMs + durationMs, - label: `${durationMs.toFixed(0)}ms`, - nodeName: effectiveSelectedNode, - }); - break; - } + for (const p of headPropagation) { + if (p.node_id) { + events.push({ type: 'head', timeMs: p.seen_slot_start_diff ?? 0, nodeName: p.node_id }); } + } - // Data columns: range from first to last column seen - const nodeColumns = dataColumnPropagation.filter(p => p.node_id && nodeMatches(effectiveSelectedNode, p.node_id)); - if (nodeColumns.length > 0) { - const times = nodeColumns.map(c => c.seen_slot_start_diff ?? 0); - const minTime = Math.min(...times); - const maxTime = Math.max(...times); + const execItems = executionData?.int_engine_new_payload ?? []; + for (const e of execItems) { + if (e.meta_client_name) { + const slotStartMs = (e.slot_start_date_time ?? 0) * 1000; + const requestedMs = (e.requested_date_time ?? 0) / 1000; + const startMs = requestedMs - slotStartMs; + const durationMs = e.duration_ms ?? 0; events.push({ - type: 'data_columns', - timeMs: minTime, - endMs: minTime !== maxTime ? maxTime : undefined, - label: `${nodeColumns.length} cols`, - nodeName: effectiveSelectedNode, + type: 'execution', + timeMs: startMs, + endMs: startMs + durationMs, + label: `${durationMs.toFixed(0)}ms`, + nodeName: e.meta_client_name, }); } - } else { - // Aggregate: show p50 for block/head, nothing for execution/data_columns - const blockTimes = blockPropagation.map(p => p.seen_slot_start_diff ?? 0).sort((a, b) => a - b); - if (blockTimes.length > 0) { - events.push({ type: 'block', timeMs: blockTimes[Math.floor(blockTimes.length * 0.5)], label: 'p50' }); - } - - const headTimes = headPropagation.map(p => p.seen_slot_start_diff ?? 0).sort((a, b) => a - b); - if (headTimes.length > 0) { - events.push({ type: 'head', timeMs: headTimes[Math.floor(headTimes.length * 0.5)], label: 'p50' }); - } + } - // Data columns aggregate: p50 of first-seen, p50 of last-seen - if (dataColumnPropagation.length > 0) { - const byNode = new Map(); - for (const c of dataColumnPropagation) { - const nid = c.node_id ?? ''; - if (!byNode.has(nid)) byNode.set(nid, []); - byNode.get(nid)!.push(c.seen_slot_start_diff ?? 0); - } - const firstTimes: number[] = []; - const lastTimes: number[] = []; - for (const times of byNode.values()) { - firstTimes.push(Math.min(...times)); - lastTimes.push(Math.max(...times)); - } - firstTimes.sort((a, b) => a - b); - lastTimes.sort((a, b) => a - b); - const firstP50 = firstTimes[Math.floor(firstTimes.length * 0.5)]; - const lastP50 = lastTimes[Math.floor(lastTimes.length * 0.5)]; - events.push({ - type: 'data_columns', - timeMs: firstP50, - endMs: firstP50 !== lastP50 ? lastP50 : undefined, - label: 'p50', - }); - } + // Data columns: group by node, produce one range event per node + const colsByNode = new Map(); + for (const c of dataColumnPropagation) { + const nid = c.node_id ?? ''; + if (!nid) continue; + if (!colsByNode.has(nid)) colsByNode.set(nid, []); + colsByNode.get(nid)!.push(c.seen_slot_start_diff ?? 0); + } + for (const [nid, times] of colsByNode) { + const minTime = Math.min(...times); + const maxTime = Math.max(...times); + events.push({ + type: 'data_columns', + timeMs: minTime, + endMs: minTime !== maxTime ? maxTime : undefined, + label: `${times.length} cols`, + nodeName: nid, + }); } return events; - }, [effectiveSelectedNode, blockPropagation, headPropagation, dataColumnPropagation, executionData]); + }, [blockPropagation, headPropagation, dataColumnPropagation, executionData]); - // Which annotation types have data + // Which annotation types have data (slot_phases is always available) const availableAnnotations = useMemo(() => { const types = new Set(annotations.map(a => a.type)); - return ANNOTATION_OPTIONS.filter(o => types.has(o.value)); + return ANNOTATION_OPTIONS.filter(o => o.value === 'slot_phases' || types.has(o.value)); }, [annotations]); if (isLoading) { @@ -293,13 +248,24 @@ export function NodeResourcesPanel({ } return ( -
+
{/* Controls */}

Node Resources

-

CPU utilization across {nodeNames.length} nodes during this slot

+

+ Data from{' '} + + Observoor + {' '} + across {nodeNames.length} nodes +

- {!effectiveSelectedNode && ( - - )}
))} @@ -356,6 +323,7 @@ export function NodeResourcesPanel({ data={filteredData} selectedNode={effectiveSelectedNode} metric={metric} + onMetricChange={setMetric} slot={slot} annotations={annotations} enabledAnnotations={enabledAnnotations} diff --git a/src/pages/ethereum/slots/components/NodeResources/types.ts b/src/pages/ethereum/slots/components/NodeResources/types.ts index b76494bf1..5c4c2f473 100644 --- a/src/pages/ethereum/slots/components/NodeResources/types.ts +++ b/src/pages/ethereum/slots/components/NodeResources/types.ts @@ -1,7 +1,9 @@ -export type AnnotationType = 'block' | 'head' | 'execution' | 'data_columns'; +export type CpuMetric = 'mean' | 'min' | 'max'; + +export type AnnotationType = 'block' | 'head' | 'execution' | 'data_columns' | 'slot_phases'; export interface AnnotationEvent { - type: AnnotationType; + type: Exclude; /** Time in milliseconds from slot start */ timeMs: number; /** Optional end time for range annotations */ @@ -12,7 +14,16 @@ export interface AnnotationEvent { nodeName?: string; } +export const ANNOTATION_COLORS: Record = { + block: '#f59e0b', + head: '#8b5cf6', + execution: '#ef4444', + data_columns: '#10b981', + slot_phases: '#6b7280', +}; + export const ANNOTATION_OPTIONS: { value: AnnotationType; label: string; description: string }[] = [ + { value: 'slot_phases', label: 'Slot Phases', description: 'Block / Attestation / Aggregation phase boundaries' }, { value: 'block', label: 'Block Arrival', description: 'When block gossip was received' }, { value: 'head', label: 'Head Update', description: 'When chain head was updated' }, { value: 'execution', label: 'Execution', description: 'Engine newPayload call duration' }, diff --git a/src/utils/ethereum.ts b/src/utils/ethereum.ts index 6d288e13c..dffc1e465 100644 --- a/src/utils/ethereum.ts +++ b/src/utils/ethereum.ts @@ -97,9 +97,26 @@ export function truncateAddress(pubkey?: string, startChars = 6, endChars = 4): return `${pubkey.slice(0, startChars)}...${pubkey.slice(-endChars)}`; } +/** + * Known consensus client names + */ +export const CONSENSUS_CLIENTS = new Set(['lighthouse', 'lodestar', 'nimbus', 'prysm', 'teku', 'grandine']); + /** * Known execution client names */ +export const EXECUTION_CLIENTS_SET = new Set(['besu', 'erigon', 'geth', 'nethermind', 'reth', 'ethrex']); + +/** + * Determine whether a client type string is a CL or EL client + */ +export function getClientLayer(clientType: string): 'CL' | 'EL' | null { + const lower = clientType.toLowerCase(); + if (CONSENSUS_CLIENTS.has(lower)) return 'CL'; + if (EXECUTION_CLIENTS_SET.has(lower)) return 'EL'; + return null; +} + const EXECUTION_CLIENTS = ['geth', 'nethermind', 'besu', 'erigon', 'reth', 'ethrex'] as const; /** From ab84241266a9bbe8e47769490e0210759d5253b7 Mon Sep 17 00:00:00 2001 From: Sam Calder-Mason Date: Thu, 12 Feb 2026 16:26:12 +1000 Subject: [PATCH 05/15] fix: resolve build and lint errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update IntEngineNewPayloadFastest → IntEngineNewPayloadFastestExecutionByNodeClass after table rename (pre-existing master issue) - Fix navigate type narrowing by using search spread instead of prev callback - Replace any casts with EChartsTooltipParam interface in tooltip formatter - Move PHASE_BOUNDARY_COLORS to module scope to fix exhaustive-deps warning - Regenerate API types from local cbt-api (removes stale max_single_core_pct) --- src/api/types.gen.ts | 8 ------- src/api/zod.gen.ts | 2 -- .../NewPayloadTab/NewPayloadTab.tsx | 4 ++-- .../timings/hooks/useEngineTimingsData.ts | 10 ++++---- .../NodeResources/CpuUtilizationChart.tsx | 23 +++++++++++-------- .../NodeResources/NodeResourcesPanel.tsx | 12 +++++----- 6 files changed, 26 insertions(+), 33 deletions(-) diff --git a/src/api/types.gen.ts b/src/api/types.gen.ts index 4c7cd6b42..f2a4b6bb9 100644 --- a/src/api/types.gen.ts +++ b/src/api/types.gen.ts @@ -4569,10 +4569,6 @@ export type FctNodeCpuUtilization = { * Maximum CPU core utilization percentage (100pct = 1 core) */ max_core_pct?: number; - /** - * Maximum single core utilization percentage (0-100pct) - */ - max_single_core_pct?: number; /** * Mean CPU core utilization percentage (100pct = 1 core) */ @@ -55469,10 +55465,6 @@ export type FctNodeCpuUtilizationServiceListData = { * Filter max_core_pct using value */ max_core_pct_value?: number; - /** - * Filter max_single_core_pct using value - */ - max_single_core_pct_value?: number; /** * Node classification for filtering (e.g. eip7870) (filter: eq) */ diff --git a/src/api/zod.gen.ts b/src/api/zod.gen.ts index 8629aa971..04009bf32 100644 --- a/src/api/zod.gen.ts +++ b/src/api/zod.gen.ts @@ -6634,7 +6634,6 @@ export const zFctNodeActiveLast24h = z.object({ export const zFctNodeCpuUtilization = z.object({ client_type: z.optional(z.string()), max_core_pct: z.optional(z.number()), - max_single_core_pct: z.optional(z.number()), mean_core_pct: z.optional(z.number()), meta_client_name: z.optional(z.string()), meta_network_name: z.optional(z.string()), @@ -69462,7 +69461,6 @@ export const zFctNodeCpuUtilizationServiceListData = z.object({ mean_core_pct_value: z.optional(z.number()), min_core_pct_value: z.optional(z.number()), max_core_pct_value: z.optional(z.number()), - max_single_core_pct_value: z.optional(z.number()), node_class_eq: z.optional(z.string()), node_class_ne: z.optional(z.string()), node_class_contains: z.optional(z.string()), diff --git a/src/pages/ethereum/execution/timings/components/NewPayloadTab/NewPayloadTab.tsx b/src/pages/ethereum/execution/timings/components/NewPayloadTab/NewPayloadTab.tsx index 9ac23028d..2fbb61ab0 100644 --- a/src/pages/ethereum/execution/timings/components/NewPayloadTab/NewPayloadTab.tsx +++ b/src/pages/ethereum/execution/timings/components/NewPayloadTab/NewPayloadTab.tsx @@ -10,7 +10,7 @@ import { ScatterAndLineChart } from '@/components/Charts/ScatterAndLine'; import { useThemeColors } from '@/hooks/useThemeColors'; import { formatSlot, getExecutionClientColor } from '@/utils'; import { ClientLogo } from '@/components/Ethereum/ClientLogo'; -import type { FctEngineNewPayloadWinrateHourly, IntEngineNewPayloadFastest } from '@/api/types.gen'; +import type { FctEngineNewPayloadWinrateHourly, IntEngineNewPayloadFastestExecutionByNodeClass } from '@/api/types.gen'; import type { EngineTimingsData } from '../../hooks/useEngineTimingsData'; import { PER_SLOT_CHART_RANGES, type TimeRange } from '../../IndexPage.types'; import { ClientVersionBreakdown } from '../ClientVersionBreakdown'; @@ -833,7 +833,7 @@ function WinrateSection({ showPerSlot, }: { hourlyRecords: FctEngineNewPayloadWinrateHourly[]; - perSlotRecords: IntEngineNewPayloadFastest[]; + perSlotRecords: IntEngineNewPayloadFastestExecutionByNodeClass[]; allClients: string[]; timeRange: TimeRange; showPerSlot: boolean; diff --git a/src/pages/ethereum/execution/timings/hooks/useEngineTimingsData.ts b/src/pages/ethereum/execution/timings/hooks/useEngineTimingsData.ts index 6b08dd9d7..934913314 100644 --- a/src/pages/ethereum/execution/timings/hooks/useEngineTimingsData.ts +++ b/src/pages/ethereum/execution/timings/hooks/useEngineTimingsData.ts @@ -8,7 +8,7 @@ import { fctEngineGetBlobsByElClientHourlyServiceList, fctEngineGetBlobsDurationChunked50MsServiceList, fctEngineNewPayloadWinrateHourlyServiceList, - intEngineNewPayloadFastestServiceList, + intEngineNewPayloadFastestExecutionByNodeClassServiceList, } from '@/api/sdk.gen'; import type { FctEngineNewPayloadByElClient, @@ -18,7 +18,7 @@ import type { FctEngineGetBlobsByElClientHourly, FctEngineGetBlobsDurationChunked50Ms, FctEngineNewPayloadWinrateHourly, - IntEngineNewPayloadFastest, + IntEngineNewPayloadFastestExecutionByNodeClass, } from '@/api/types.gen'; import { useNetwork } from '@/hooks/useNetwork'; import { fetchAllPages } from '@/utils/api-pagination'; @@ -47,7 +47,7 @@ export interface EngineTimingsData { winrateHourly: FctEngineNewPayloadWinrateHourly[]; // newPayload winrate (per-slot, for short time ranges) - winratePerSlot: IntEngineNewPayloadFastest[]; + winratePerSlot: IntEngineNewPayloadFastestExecutionByNodeClass[]; } export type ActiveTab = 'newPayload' | 'getBlobs'; @@ -275,8 +275,8 @@ export function useEngineTimingsData({ { queryKey: ['engine-timings', 'winrate-per-slot', hourlyStart, hourlyEnd, referenceNodesOnly], queryFn: ({ signal }) => - fetchAllPages( - intEngineNewPayloadFastestServiceList, + fetchAllPages( + intEngineNewPayloadFastestExecutionByNodeClassServiceList, { query: { slot_start_date_time_gte: hourlyStart, diff --git a/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx b/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx index 11854ded3..2702b9549 100644 --- a/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx @@ -65,6 +65,16 @@ interface CpuUtilizationChartProps { enabledAnnotations: Set; } +/** Slot phase boundary colors: cyan (block), green (attestation), amber (aggregation) */ +const PHASE_BOUNDARY_COLORS = ['#22d3ee', '#22c55e', '#f59e0b']; + +interface EChartsTooltipParam { + marker: string; + seriesName: string; + value: [number, number] | number; + axisValue?: number | string; +} + const BUCKET_SIZE = 0.25; const toBucket = (offsetSec: number): number => Math.round(offsetSec / BUCKET_SIZE) * BUCKET_SIZE; const avg = (arr: number[]): number => arr.reduce((s, v) => s + v, 0) / arr.length; @@ -289,10 +299,6 @@ export function CpuUtilizationChart({ return areas; }, [annotations, enabledAnnotations, selectedNode]); - // Slot phase boundary markLines (e.g. attestation deadline at 4s, aggregation at 8s) - // Colors match the live slot view: cyan (block), green (attestation), amber (aggregation) - const PHASE_BOUNDARY_COLORS = ['#22d3ee', '#22c55e', '#f59e0b']; - const markLines = useMemo((): MarkLineConfig[] => { if (!enabledAnnotations.has('slot_phases')) return []; @@ -374,20 +380,17 @@ export function CpuUtilizationChart({ markAreas={markAreas} syncGroup="slot-time" tooltipFormatter={(params: unknown) => { - const items = Array.isArray(params) ? params : [params]; + const items = (Array.isArray(params) ? params : [params]) as EChartsTooltipParam[]; if (items.length === 0) return ''; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const first = items[0] as any; + const first = items[0]; const xVal = Array.isArray(first.value) ? first.value[0] : first.axisValue; const timeStr = typeof xVal === 'number' ? `${xVal.toFixed(2)}s` : `${xVal}s`; let html = `
`; html += `
${timeStr}
`; - for (const item of items) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const p = item as any; + for (const p of items) { const val = Array.isArray(p.value) ? p.value[1] : p.value; if (val == null) continue; html += `
`; diff --git a/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx b/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx index 147a778ff..f976ff009 100644 --- a/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx @@ -67,12 +67,12 @@ export function NodeResourcesPanel({ navigate({ to: '/ethereum/slots/$slot', params: { slot: String(slot) }, - search: prev => ({ ...prev, refNodes: value || undefined }), + search: { ...search, refNodes: value || undefined }, replace: true, resetScroll: false, }); }, - [navigate, slot] + [navigate, slot, search] ); const setSelectedNode = useCallback( @@ -80,12 +80,12 @@ export function NodeResourcesPanel({ navigate({ to: '/ethereum/slots/$slot', params: { slot: String(slot) }, - search: prev => ({ ...prev, node: value ?? undefined }), + search: { ...search, node: value ?? undefined }, replace: true, resetScroll: false, }); }, - [navigate, slot] + [navigate, slot, search] ); const setMetric = useCallback( @@ -93,12 +93,12 @@ export function NodeResourcesPanel({ navigate({ to: '/ethereum/slots/$slot', params: { slot: String(slot) }, - search: prev => ({ ...prev, metric: value === 'mean' ? undefined : value }), + search: { ...search, metric: value === 'mean' ? undefined : value }, replace: true, resetScroll: false, }); }, - [navigate, slot] + [navigate, slot, search] ); const toggleAnnotation = useCallback((type: AnnotationType) => { From 79bf6e9d1d41f6212aada2315286b4fdd7d9b5b8 Mon Sep 17 00:00:00 2001 From: Sam Calder-Mason Date: Thu, 12 Feb 2026 17:03:25 +1000 Subject: [PATCH 06/15] refactor: deduplicate client name lists into single source of truth --- .../components/NodeResources/NodeResourcesPanel.tsx | 4 ++-- .../xatu/locally-built-blocks/utils/parse-clients.ts | 10 +--------- src/utils/ethereum.ts | 10 +++++----- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx b/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx index f976ff009..605130de7 100644 --- a/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx @@ -6,7 +6,7 @@ import { Card } from '@/components/Layout/Card'; import { Checkbox } from '@/components/Forms/Checkbox'; import { ReferenceNodesInfoDialog } from '@/pages/ethereum/execution/timings/components/ReferenceNodesInfoDialog'; import { extractClusterFromNodeName } from '@/constants/eip7870'; -import { CONSENSUS_CLIENTS, EXECUTION_CLIENTS_SET } from '@/utils/ethereum'; +import { CONSENSUS_CLIENTS_SET, EXECUTION_CLIENTS_SET } from '@/utils/ethereum'; import { intEngineNewPayloadServiceListOptions } from '@/api/@tanstack/react-query.gen'; import type { FctBlockFirstSeenByNode, @@ -137,7 +137,7 @@ export function NodeResourcesPanel({ if (!name) continue; const existing = info.get(name) ?? { cl: '', el: '' }; - if (CONSENSUS_CLIENTS.has(clientType) && !existing.cl) { + if (CONSENSUS_CLIENTS_SET.has(clientType) && !existing.cl) { existing.cl = clientType; } else if (EXECUTION_CLIENTS_SET.has(clientType) && !existing.el) { existing.el = clientType; diff --git a/src/pages/xatu/locally-built-blocks/utils/parse-clients.ts b/src/pages/xatu/locally-built-blocks/utils/parse-clients.ts index 6fbcad3fb..3b8f61052 100644 --- a/src/pages/xatu/locally-built-blocks/utils/parse-clients.ts +++ b/src/pages/xatu/locally-built-blocks/utils/parse-clients.ts @@ -1,12 +1,4 @@ -/** - * Known execution client names - */ -const EXECUTION_CLIENTS = ['geth', 'nethermind', 'besu', 'erigon', 'reth'] as const; - -/** - * Known consensus client names - */ -const CONSENSUS_CLIENTS = ['lighthouse', 'prysm', 'teku', 'nimbus', 'lodestar', 'grandine'] as const; +import { CONSENSUS_CLIENTS, EXECUTION_CLIENTS } from '@/utils/ethereum'; /** * Parse the meta_client_name to extract execution and consensus client names diff --git a/src/utils/ethereum.ts b/src/utils/ethereum.ts index dffc1e465..891deb288 100644 --- a/src/utils/ethereum.ts +++ b/src/utils/ethereum.ts @@ -100,25 +100,25 @@ export function truncateAddress(pubkey?: string, startChars = 6, endChars = 4): /** * Known consensus client names */ -export const CONSENSUS_CLIENTS = new Set(['lighthouse', 'lodestar', 'nimbus', 'prysm', 'teku', 'grandine']); +export const CONSENSUS_CLIENTS = ['lighthouse', 'lodestar', 'nimbus', 'prysm', 'teku', 'grandine'] as const; +export const CONSENSUS_CLIENTS_SET = new Set(CONSENSUS_CLIENTS); /** * Known execution client names */ -export const EXECUTION_CLIENTS_SET = new Set(['besu', 'erigon', 'geth', 'nethermind', 'reth', 'ethrex']); +export const EXECUTION_CLIENTS = ['geth', 'nethermind', 'besu', 'erigon', 'reth', 'ethrex'] as const; +export const EXECUTION_CLIENTS_SET = new Set(EXECUTION_CLIENTS); /** * Determine whether a client type string is a CL or EL client */ export function getClientLayer(clientType: string): 'CL' | 'EL' | null { const lower = clientType.toLowerCase(); - if (CONSENSUS_CLIENTS.has(lower)) return 'CL'; + if (CONSENSUS_CLIENTS_SET.has(lower)) return 'CL'; if (EXECUTION_CLIENTS_SET.has(lower)) return 'EL'; return null; } -const EXECUTION_CLIENTS = ['geth', 'nethermind', 'besu', 'erigon', 'reth', 'ethrex'] as const; - /** * Official brand colors for Ethereum execution clients */ From b83aa141f4383ea65cabe38ee87631f0df8d0bcb Mon Sep 17 00:00:00 2001 From: Sam Calder-Mason Date: Thu, 12 Feb 2026 18:11:20 +1000 Subject: [PATCH 07/15] fix(slots): align node resource annotations and CL/EL layer detection --- .../NodeResources/NodeResourcesPanel.tsx | 43 ++++++++++++++----- src/utils/ethereum.test.ts | 34 ++++++++++++++- src/utils/ethereum.ts | 2 + 3 files changed, 68 insertions(+), 11 deletions(-) diff --git a/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx b/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx index 605130de7..b7d1e4b73 100644 --- a/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx @@ -6,7 +6,7 @@ import { Card } from '@/components/Layout/Card'; import { Checkbox } from '@/components/Forms/Checkbox'; import { ReferenceNodesInfoDialog } from '@/pages/ethereum/execution/timings/components/ReferenceNodesInfoDialog'; import { extractClusterFromNodeName } from '@/constants/eip7870'; -import { CONSENSUS_CLIENTS_SET, EXECUTION_CLIENTS_SET } from '@/utils/ethereum'; +import { CONSENSUS_CLIENTS_SET, EXECUTION_CLIENTS_SET, getClientLayer } from '@/utils/ethereum'; import { intEngineNewPayloadServiceListOptions } from '@/api/@tanstack/react-query.gen'; import type { FctBlockFirstSeenByNode, @@ -26,6 +26,16 @@ import { export type { CpuMetric } from './types'; +function nodeMatches(cpuNodeName: string, eventNodeName: string): boolean { + const short = cpuNodeName.split('/').pop() ?? cpuNodeName; + return ( + eventNodeName === short || + eventNodeName === cpuNodeName || + short.includes(eventNodeName) || + eventNodeName.includes(short) + ); +} + interface NodeResourcesPanelProps { slot: number; blockPropagation: FctBlockFirstSeenByNode[]; @@ -137,9 +147,11 @@ export function NodeResourcesPanel({ if (!name) continue; const existing = info.get(name) ?? { cl: '', el: '' }; - if (CONSENSUS_CLIENTS_SET.has(clientType) && !existing.cl) { + const layer = getClientLayer(clientType); + + if ((CONSENSUS_CLIENTS_SET.has(clientType) || layer === 'CL') && !existing.cl) { existing.cl = clientType; - } else if (EXECUTION_CLIENTS_SET.has(clientType) && !existing.el) { + } else if ((EXECUTION_CLIENTS_SET.has(clientType) || layer === 'EL') && !existing.el) { existing.el = clientType; } info.set(name, existing); @@ -153,22 +165,32 @@ export function NodeResourcesPanel({ // Build raw per-node annotation events (chart handles aggregation) const annotations = useMemo((): AnnotationEvent[] => { const events: AnnotationEvent[] = []; + const filteredNodeSet = new Set(nodeNames); + const isIncludedNode = (nodeName: string): boolean => { + if (filteredNodeSet.has(nodeName)) return true; + for (const filteredNodeName of filteredNodeSet) { + if (nodeMatches(filteredNodeName, nodeName)) return true; + } + return false; + }; for (const p of blockPropagation) { - if (p.node_id) { - events.push({ type: 'block', timeMs: p.seen_slot_start_diff ?? 0, nodeName: p.node_id }); + const nodeName = p.meta_client_name ?? p.node_id; + if (nodeName && isIncludedNode(nodeName)) { + events.push({ type: 'block', timeMs: p.seen_slot_start_diff ?? 0, nodeName }); } } for (const p of headPropagation) { - if (p.node_id) { - events.push({ type: 'head', timeMs: p.seen_slot_start_diff ?? 0, nodeName: p.node_id }); + const nodeName = p.meta_client_name ?? p.node_id; + if (nodeName && isIncludedNode(nodeName)) { + events.push({ type: 'head', timeMs: p.seen_slot_start_diff ?? 0, nodeName }); } } const execItems = executionData?.int_engine_new_payload ?? []; for (const e of execItems) { - if (e.meta_client_name) { + if (e.meta_client_name && isIncludedNode(e.meta_client_name)) { const slotStartMs = (e.slot_start_date_time ?? 0) * 1000; const requestedMs = (e.requested_date_time ?? 0) / 1000; const startMs = requestedMs - slotStartMs; @@ -186,8 +208,9 @@ export function NodeResourcesPanel({ // Data columns: group by node, produce one range event per node const colsByNode = new Map(); for (const c of dataColumnPropagation) { - const nid = c.node_id ?? ''; + const nid = c.meta_client_name ?? c.node_id ?? ''; if (!nid) continue; + if (!isIncludedNode(nid)) continue; if (!colsByNode.has(nid)) colsByNode.set(nid, []); colsByNode.get(nid)!.push(c.seen_slot_start_diff ?? 0); } @@ -204,7 +227,7 @@ export function NodeResourcesPanel({ } return events; - }, [blockPropagation, headPropagation, dataColumnPropagation, executionData]); + }, [blockPropagation, headPropagation, dataColumnPropagation, executionData, nodeNames]); // Which annotation types have data (slot_phases is always available) const availableAnnotations = useMemo(() => { diff --git a/src/utils/ethereum.test.ts b/src/utils/ethereum.test.ts index d761ac706..4a2ffe112 100644 --- a/src/utils/ethereum.test.ts +++ b/src/utils/ethereum.test.ts @@ -1,5 +1,13 @@ import { describe, it, expect } from 'vitest'; -import { weiToEth, ethToWei, weiToGwei, gweiToWei, truncateAddress, parseExecutionClient } from './ethereum'; +import { + weiToEth, + ethToWei, + weiToGwei, + gweiToWei, + truncateAddress, + parseExecutionClient, + getClientLayer, +} from './ethereum'; describe('weiToEth', () => { it('should convert 1 ETH in wei to ETH', () => { @@ -179,3 +187,27 @@ describe('parseExecutionClient', () => { expect(parseExecutionClient('Nethermind / v1.25.4 ')).toBe('Nethermind v1.25.4'); }); }); + +describe('getClientLayer', () => { + it('should classify known consensus clients as CL', () => { + expect(getClientLayer('lighthouse')).toBe('CL'); + expect(getClientLayer('TeKu')).toBe('CL'); + }); + + it('should classify known execution clients as EL', () => { + expect(getClientLayer('geth')).toBe('EL'); + expect(getClientLayer('Nethermind')).toBe('EL'); + }); + + it('should classify CL/EL aliases case-insensitively', () => { + expect(getClientLayer('CL')).toBe('CL'); + expect(getClientLayer('cl')).toBe('CL'); + expect(getClientLayer('EL')).toBe('EL'); + expect(getClientLayer('el')).toBe('EL'); + }); + + it('should return null for unknown client types', () => { + expect(getClientLayer('')).toBeNull(); + expect(getClientLayer('unknown-client')).toBeNull(); + }); +}); diff --git a/src/utils/ethereum.ts b/src/utils/ethereum.ts index 891deb288..3084590bb 100644 --- a/src/utils/ethereum.ts +++ b/src/utils/ethereum.ts @@ -114,6 +114,8 @@ export const EXECUTION_CLIENTS_SET = new Set(EXECUTION_CLIENTS); */ export function getClientLayer(clientType: string): 'CL' | 'EL' | null { const lower = clientType.toLowerCase(); + if (lower === 'cl') return 'CL'; + if (lower === 'el') return 'EL'; if (CONSENSUS_CLIENTS_SET.has(lower)) return 'CL'; if (EXECUTION_CLIENTS_SET.has(lower)) return 'EL'; return null; From 379de6004b718af3216ce87299dd1ac1f2bc31c3 Mon Sep 17 00:00:00 2001 From: Sam Calder-Mason Date: Thu, 12 Feb 2026 19:33:38 +1000 Subject: [PATCH 08/15] =?UTF-8?q?rename:=20fct=5Fnode=5Fcpu=5Futilization?= =?UTF-8?q?=20=E2=86=92=20fct=5Fnode=5Fcpu=5Futilization=5Fby=5Fprocess?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regenerated API types and updated component/hook imports to match the renamed xatu-cbt table. --- src/api/@tanstack/react-query.gen.ts | 58 ++++++++++--------- src/api/index.ts | 30 +++++----- src/api/sdk.gen.ts | 48 +++++++-------- src/api/types.gen.ts | 56 +++++++++--------- src/api/zod.gen.ts | 22 +++---- .../NodeResources/CpuUtilizationChart.tsx | 6 +- .../useSlotNodeResources.ts | 10 ++-- 7 files changed, 118 insertions(+), 112 deletions(-) diff --git a/src/api/@tanstack/react-query.gen.ts b/src/api/@tanstack/react-query.gen.ts index d588ae456..95bdf7996 100644 --- a/src/api/@tanstack/react-query.gen.ts +++ b/src/api/@tanstack/react-query.gen.ts @@ -184,8 +184,8 @@ import { fctMissedSlotRateHourlyServiceList, fctNodeActiveLast24hServiceGet, fctNodeActiveLast24hServiceList, - fctNodeCpuUtilizationServiceGet, - fctNodeCpuUtilizationServiceList, + fctNodeCpuUtilizationByProcessServiceGet, + fctNodeCpuUtilizationByProcessServiceList, fctOpcodeGasByOpcodeDailyServiceGet, fctOpcodeGasByOpcodeDailyServiceList, fctOpcodeGasByOpcodeHourlyServiceGet, @@ -903,12 +903,12 @@ import type { FctNodeActiveLast24hServiceListData, FctNodeActiveLast24hServiceListError, FctNodeActiveLast24hServiceListResponse, - FctNodeCpuUtilizationServiceGetData, - FctNodeCpuUtilizationServiceGetError, - FctNodeCpuUtilizationServiceGetResponse, - FctNodeCpuUtilizationServiceListData, - FctNodeCpuUtilizationServiceListError, - FctNodeCpuUtilizationServiceListResponse, + FctNodeCpuUtilizationByProcessServiceGetData, + FctNodeCpuUtilizationByProcessServiceGetError, + FctNodeCpuUtilizationByProcessServiceGetResponse, + FctNodeCpuUtilizationByProcessServiceListData, + FctNodeCpuUtilizationByProcessServiceListError, + FctNodeCpuUtilizationByProcessServiceListResponse, FctOpcodeGasByOpcodeDailyServiceGetData, FctOpcodeGasByOpcodeDailyServiceGetError, FctOpcodeGasByOpcodeDailyServiceGetResponse, @@ -6683,23 +6683,26 @@ export const fctNodeActiveLast24hServiceGetOptions = (options: Options) => - createQueryKey('fctNodeCpuUtilizationServiceList', options); +export const fctNodeCpuUtilizationByProcessServiceListQueryKey = ( + options?: Options +) => createQueryKey('fctNodeCpuUtilizationByProcessServiceList', options); /** * List records * * Retrieve paginated results with optional filtering */ -export const fctNodeCpuUtilizationServiceListOptions = (options?: Options) => +export const fctNodeCpuUtilizationByProcessServiceListOptions = ( + options?: Options +) => queryOptions< - FctNodeCpuUtilizationServiceListResponse, - FctNodeCpuUtilizationServiceListError, - FctNodeCpuUtilizationServiceListResponse, - ReturnType + FctNodeCpuUtilizationByProcessServiceListResponse, + FctNodeCpuUtilizationByProcessServiceListError, + FctNodeCpuUtilizationByProcessServiceListResponse, + ReturnType >({ queryFn: async ({ queryKey, signal }) => { - const { data } = await fctNodeCpuUtilizationServiceList({ + const { data } = await fctNodeCpuUtilizationByProcessServiceList({ ...options, ...queryKey[0], signal, @@ -6707,26 +6710,29 @@ export const fctNodeCpuUtilizationServiceListOptions = (options?: Options) => - createQueryKey('fctNodeCpuUtilizationServiceGet', options); +export const fctNodeCpuUtilizationByProcessServiceGetQueryKey = ( + options: Options +) => createQueryKey('fctNodeCpuUtilizationByProcessServiceGet', options); /** * Get record * * Retrieve a single record by wallclock_slot_start_date_time */ -export const fctNodeCpuUtilizationServiceGetOptions = (options: Options) => +export const fctNodeCpuUtilizationByProcessServiceGetOptions = ( + options: Options +) => queryOptions< - FctNodeCpuUtilizationServiceGetResponse, - FctNodeCpuUtilizationServiceGetError, - FctNodeCpuUtilizationServiceGetResponse, - ReturnType + FctNodeCpuUtilizationByProcessServiceGetResponse, + FctNodeCpuUtilizationByProcessServiceGetError, + FctNodeCpuUtilizationByProcessServiceGetResponse, + ReturnType >({ queryFn: async ({ queryKey, signal }) => { - const { data } = await fctNodeCpuUtilizationServiceGet({ + const { data } = await fctNodeCpuUtilizationByProcessServiceGet({ ...options, ...queryKey[0], signal, @@ -6734,7 +6740,7 @@ export const fctNodeCpuUtilizationServiceGetOptions = (options: Options( - options?: Options +export const fctNodeCpuUtilizationByProcessServiceList = ( + options?: Options ) => (options?.client ?? client).get< - FctNodeCpuUtilizationServiceListResponses, - FctNodeCpuUtilizationServiceListErrors, + FctNodeCpuUtilizationByProcessServiceListResponses, + FctNodeCpuUtilizationByProcessServiceListErrors, ThrowOnError >({ - requestValidator: async data => await zFctNodeCpuUtilizationServiceListData.parseAsync(data), - responseValidator: async data => await zFctNodeCpuUtilizationServiceListResponse.parseAsync(data), - url: '/api/v1/fct_node_cpu_utilization', + requestValidator: async data => await zFctNodeCpuUtilizationByProcessServiceListData.parseAsync(data), + responseValidator: async data => await zFctNodeCpuUtilizationByProcessServiceListResponse.parseAsync(data), + url: '/api/v1/fct_node_cpu_utilization_by_process', ...options, }); @@ -5226,17 +5226,17 @@ export const fctNodeCpuUtilizationServiceList = ( - options: Options +export const fctNodeCpuUtilizationByProcessServiceGet = ( + options: Options ) => (options.client ?? client).get< - FctNodeCpuUtilizationServiceGetResponses, - FctNodeCpuUtilizationServiceGetErrors, + FctNodeCpuUtilizationByProcessServiceGetResponses, + FctNodeCpuUtilizationByProcessServiceGetErrors, ThrowOnError >({ - requestValidator: async data => await zFctNodeCpuUtilizationServiceGetData.parseAsync(data), - responseValidator: async data => await zFctNodeCpuUtilizationServiceGetResponse.parseAsync(data), - url: '/api/v1/fct_node_cpu_utilization/{wallclock_slot_start_date_time}', + requestValidator: async data => await zFctNodeCpuUtilizationByProcessServiceGetData.parseAsync(data), + responseValidator: async data => await zFctNodeCpuUtilizationByProcessServiceGetResponse.parseAsync(data), + url: '/api/v1/fct_node_cpu_utilization_by_process/{wallclock_slot_start_date_time}', ...options, }); diff --git a/src/api/types.gen.ts b/src/api/types.gen.ts index f2a4b6bb9..3cdab65f7 100644 --- a/src/api/types.gen.ts +++ b/src/api/types.gen.ts @@ -4560,7 +4560,7 @@ export type FctNodeActiveLast24h = { username?: string; }; -export type FctNodeCpuUtilization = { +export type FctNodeCpuUtilizationByProcess = { /** * Client type: CL or EL */ @@ -6205,10 +6205,10 @@ export type GetFctNodeActiveLast24hResponse = { }; /** - * Response for getting a single fct_node_cpu_utilization record + * Response for getting a single fct_node_cpu_utilization_by_process record */ -export type GetFctNodeCpuUtilizationResponse = { - item?: FctNodeCpuUtilization; +export type GetFctNodeCpuUtilizationByProcessResponse = { + item?: FctNodeCpuUtilizationByProcess; }; /** @@ -10702,13 +10702,13 @@ export type ListFctNodeActiveLast24hResponse = { }; /** - * Response for listing fct_node_cpu_utilization records + * Response for listing fct_node_cpu_utilization_by_process records */ -export type ListFctNodeCpuUtilizationResponse = { +export type ListFctNodeCpuUtilizationByProcessResponse = { /** - * The list of fct_node_cpu_utilization. + * The list of fct_node_cpu_utilization_by_process. */ - fct_node_cpu_utilization?: Array; + fct_node_cpu_utilization_by_process?: Array; /** * A token, which can be sent as `page_token` to retrieve the next page. If this field is omitted, there are no subsequent pages. */ @@ -55101,7 +55101,7 @@ export type FctNodeActiveLast24hServiceGetResponses = { export type FctNodeActiveLast24hServiceGetResponse = FctNodeActiveLast24hServiceGetResponses[keyof FctNodeActiveLast24hServiceGetResponses]; -export type FctNodeCpuUtilizationServiceListData = { +export type FctNodeCpuUtilizationByProcessServiceListData = { body?: never; path?: never; query?: { @@ -55502,11 +55502,11 @@ export type FctNodeCpuUtilizationServiceListData = { */ node_class_not_in_values?: string; /** - * The maximum number of fct_node_cpu_utilization to return. If unspecified, at most 100 items will be returned. The maximum value is 10000; values above 10000 will be coerced to 10000. + * The maximum number of fct_node_cpu_utilization_by_process to return. If unspecified, at most 100 items will be returned. The maximum value is 10000; values above 10000 will be coerced to 10000. */ page_size?: number; /** - * A page token, received from a previous `ListFctNodeCpuUtilization` call. Provide this to retrieve the subsequent page. + * A page token, received from a previous `ListFctNodeCpuUtilizationByProcess` call. Provide this to retrieve the subsequent page. */ page_token?: string; /** @@ -55514,30 +55514,30 @@ export type FctNodeCpuUtilizationServiceListData = { */ order_by?: string; }; - url: '/api/v1/fct_node_cpu_utilization'; + url: '/api/v1/fct_node_cpu_utilization_by_process'; }; -export type FctNodeCpuUtilizationServiceListErrors = { +export type FctNodeCpuUtilizationByProcessServiceListErrors = { /** * Default error response */ default: Status; }; -export type FctNodeCpuUtilizationServiceListError = - FctNodeCpuUtilizationServiceListErrors[keyof FctNodeCpuUtilizationServiceListErrors]; +export type FctNodeCpuUtilizationByProcessServiceListError = + FctNodeCpuUtilizationByProcessServiceListErrors[keyof FctNodeCpuUtilizationByProcessServiceListErrors]; -export type FctNodeCpuUtilizationServiceListResponses = { +export type FctNodeCpuUtilizationByProcessServiceListResponses = { /** * OK */ - 200: ListFctNodeCpuUtilizationResponse; + 200: ListFctNodeCpuUtilizationByProcessResponse; }; -export type FctNodeCpuUtilizationServiceListResponse = - FctNodeCpuUtilizationServiceListResponses[keyof FctNodeCpuUtilizationServiceListResponses]; +export type FctNodeCpuUtilizationByProcessServiceListResponse = + FctNodeCpuUtilizationByProcessServiceListResponses[keyof FctNodeCpuUtilizationByProcessServiceListResponses]; -export type FctNodeCpuUtilizationServiceGetData = { +export type FctNodeCpuUtilizationByProcessServiceGetData = { body?: never; path: { /** @@ -55546,28 +55546,28 @@ export type FctNodeCpuUtilizationServiceGetData = { wallclock_slot_start_date_time: number; }; query?: never; - url: '/api/v1/fct_node_cpu_utilization/{wallclock_slot_start_date_time}'; + url: '/api/v1/fct_node_cpu_utilization_by_process/{wallclock_slot_start_date_time}'; }; -export type FctNodeCpuUtilizationServiceGetErrors = { +export type FctNodeCpuUtilizationByProcessServiceGetErrors = { /** * Default error response */ default: Status; }; -export type FctNodeCpuUtilizationServiceGetError = - FctNodeCpuUtilizationServiceGetErrors[keyof FctNodeCpuUtilizationServiceGetErrors]; +export type FctNodeCpuUtilizationByProcessServiceGetError = + FctNodeCpuUtilizationByProcessServiceGetErrors[keyof FctNodeCpuUtilizationByProcessServiceGetErrors]; -export type FctNodeCpuUtilizationServiceGetResponses = { +export type FctNodeCpuUtilizationByProcessServiceGetResponses = { /** * OK */ - 200: GetFctNodeCpuUtilizationResponse; + 200: GetFctNodeCpuUtilizationByProcessResponse; }; -export type FctNodeCpuUtilizationServiceGetResponse = - FctNodeCpuUtilizationServiceGetResponses[keyof FctNodeCpuUtilizationServiceGetResponses]; +export type FctNodeCpuUtilizationByProcessServiceGetResponse = + FctNodeCpuUtilizationByProcessServiceGetResponses[keyof FctNodeCpuUtilizationByProcessServiceGetResponses]; export type FctOpcodeGasByOpcodeDailyServiceListData = { body?: never; diff --git a/src/api/zod.gen.ts b/src/api/zod.gen.ts index 04009bf32..967e48d38 100644 --- a/src/api/zod.gen.ts +++ b/src/api/zod.gen.ts @@ -6631,7 +6631,7 @@ export const zFctNodeActiveLast24h = z.object({ username: z.optional(z.string()), }); -export const zFctNodeCpuUtilization = z.object({ +export const zFctNodeCpuUtilizationByProcess = z.object({ client_type: z.optional(z.string()), max_core_pct: z.optional(z.number()), mean_core_pct: z.optional(z.number()), @@ -8649,10 +8649,10 @@ export const zGetFctNodeActiveLast24hResponse = z.object({ }); /** - * Response for getting a single fct_node_cpu_utilization record + * Response for getting a single fct_node_cpu_utilization_by_process record */ -export const zGetFctNodeCpuUtilizationResponse = z.object({ - item: z.optional(zFctNodeCpuUtilization), +export const zGetFctNodeCpuUtilizationByProcessResponse = z.object({ + item: z.optional(zFctNodeCpuUtilizationByProcess), }); /** @@ -13806,10 +13806,10 @@ export const zListFctNodeActiveLast24hResponse = z.object({ }); /** - * Response for listing fct_node_cpu_utilization records + * Response for listing fct_node_cpu_utilization_by_process records */ -export const zListFctNodeCpuUtilizationResponse = z.object({ - fct_node_cpu_utilization: z.optional(z.array(zFctNodeCpuUtilization)), +export const zListFctNodeCpuUtilizationByProcessResponse = z.object({ + fct_node_cpu_utilization_by_process: z.optional(z.array(zFctNodeCpuUtilizationByProcess)), next_page_token: z.optional(z.string()), }); @@ -68966,7 +68966,7 @@ export const zFctNodeActiveLast24hServiceGetData = z.object({ */ export const zFctNodeActiveLast24hServiceGetResponse = zGetFctNodeActiveLast24hResponse; -export const zFctNodeCpuUtilizationServiceListData = z.object({ +export const zFctNodeCpuUtilizationByProcessServiceListData = z.object({ body: z.optional(z.never()), path: z.optional(z.never()), query: z.optional( @@ -69487,9 +69487,9 @@ export const zFctNodeCpuUtilizationServiceListData = z.object({ /** * OK */ -export const zFctNodeCpuUtilizationServiceListResponse = zListFctNodeCpuUtilizationResponse; +export const zFctNodeCpuUtilizationByProcessServiceListResponse = zListFctNodeCpuUtilizationByProcessResponse; -export const zFctNodeCpuUtilizationServiceGetData = z.object({ +export const zFctNodeCpuUtilizationByProcessServiceGetData = z.object({ body: z.optional(z.never()), path: z.object({ wallclock_slot_start_date_time: z.coerce @@ -69509,7 +69509,7 @@ export const zFctNodeCpuUtilizationServiceGetData = z.object({ /** * OK */ -export const zFctNodeCpuUtilizationServiceGetResponse = zGetFctNodeCpuUtilizationResponse; +export const zFctNodeCpuUtilizationByProcessServiceGetResponse = zGetFctNodeCpuUtilizationByProcessResponse; export const zFctOpcodeGasByOpcodeDailyServiceListData = z.object({ body: z.optional(z.never()), diff --git a/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx b/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx index 2702b9549..b46eeb081 100644 --- a/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx @@ -6,7 +6,7 @@ import { getDataVizColors, getClientLayer } from '@/utils'; import { DEFAULT_BEACON_SLOT_PHASES } from '@/utils/beacon'; import { ClientLogo } from '@/components/Ethereum/ClientLogo'; import { SelectMenu } from '@/components/Forms/SelectMenu'; -import type { FctNodeCpuUtilization } from '@/api/types.gen'; +import type { FctNodeCpuUtilizationByProcess } from '@/api/types.gen'; import { ANNOTATION_COLORS, type CpuMetric, type AnnotationType, type AnnotationEvent } from './types'; function usToSeconds(us: number): number { @@ -56,7 +56,7 @@ interface BucketAgg { } interface CpuUtilizationChartProps { - data: FctNodeCpuUtilization[]; + data: FctNodeCpuUtilizationByProcess[]; selectedNode: string | null; metric: CpuMetric; onMetricChange: (metric: CpuMetric) => void; @@ -100,7 +100,7 @@ export function CpuUtilizationChart({ let resolvedClClient = ''; let resolvedElClient = ''; - const bucketData = (items: FctNodeCpuUtilization[]): Map => { + const bucketData = (items: FctNodeCpuUtilizationByProcess[]): Map => { const buckets = new Map(); for (const d of items) { const offset = usToSeconds((d.window_start ?? 0) - slotStartUs); diff --git a/src/pages/ethereum/slots/hooks/useSlotNodeResources/useSlotNodeResources.ts b/src/pages/ethereum/slots/hooks/useSlotNodeResources/useSlotNodeResources.ts index d810d84dc..ed3a14ef1 100644 --- a/src/pages/ethereum/slots/hooks/useSlotNodeResources/useSlotNodeResources.ts +++ b/src/pages/ethereum/slots/hooks/useSlotNodeResources/useSlotNodeResources.ts @@ -1,14 +1,14 @@ import { useQuery } from '@tanstack/react-query'; -import { fctNodeCpuUtilizationServiceListOptions } from '@/api/@tanstack/react-query.gen'; +import { fctNodeCpuUtilizationByProcessServiceListOptions } from '@/api/@tanstack/react-query.gen'; import { useNetwork } from '@/hooks/useNetwork'; import { slotToTimestamp } from '@/utils/beacon'; -import type { FctNodeCpuUtilization } from '@/api/types.gen'; +import type { FctNodeCpuUtilizationByProcess } from '@/api/types.gen'; /** cbt-api returns DateTime64(3) fields as microseconds */ const SECONDS_TO_MICROSECONDS = 1_000_000; export interface UseSlotNodeResourcesResult { - data: FctNodeCpuUtilization[] | null; + data: FctNodeCpuUtilizationByProcess[] | null; isLoading: boolean; error: Error | null; } @@ -19,7 +19,7 @@ export function useSlotNodeResources(slot: number): UseSlotNodeResourcesResult { const slotTimestampUs = slotTimestamp * SECONDS_TO_MICROSECONDS; const { data, isLoading, error } = useQuery({ - ...fctNodeCpuUtilizationServiceListOptions({ + ...fctNodeCpuUtilizationByProcessServiceListOptions({ query: { wallclock_slot_start_date_time_eq: slotTimestampUs, page_size: 10000, @@ -28,7 +28,7 @@ export function useSlotNodeResources(slot: number): UseSlotNodeResourcesResult { enabled: !!currentNetwork && slotTimestamp > 0, }); - const cpuData = data?.fct_node_cpu_utilization ?? null; + const cpuData = data?.fct_node_cpu_utilization_by_process ?? null; return { data: cpuData, From 269503b56f871c2fb6bc846ae7b34e57eb190341 Mon Sep 17 00:00:00 2001 From: Sam Calder-Mason Date: Thu, 12 Feb 2026 20:58:35 +1000 Subject: [PATCH 09/15] feat(slots): add memory, disk I/O, and network charts to node resources Add three new resource charts alongside existing CPU utilization: - Memory Usage: RSS total/anon/file/swap per CL/EL process - Disk I/O: read/write bytes with CL/EL breakdown per node - Network I/O: traffic by port label (P2P, discovery, etc.) with beacon API/RPC ports hidden by default Resource type tabs allow switching between charts. All charts share the same annotation overlays, node selector, and sync group. --- src/api/@tanstack/react-query.gen.ts | 196 ++ src/api/index.ts | 45 + src/api/sdk.gen.ts | 144 ++ src/api/types.gen.ts | 1828 ++++++++++++++ src/api/zod.gen.ts | 2188 +++++++++++++++++ .../components/NodeResources/DiskIoChart.tsx | 341 +++ .../NodeResources/MemoryUsageChart.tsx | 356 +++ .../NodeResources/NetworkIoChart.tsx | 296 +++ .../NodeResources/NodeResourcesPanel.tsx | 179 +- .../slots/components/NodeResources/types.ts | 4 + .../slots/hooks/useSlotNodeDiskIo/index.ts | 2 + .../useSlotNodeDiskIo/useSlotNodeDiskIo.ts | 35 + .../slots/hooks/useSlotNodeMemory/index.ts | 2 + .../useSlotNodeMemory/useSlotNodeMemory.ts | 35 + .../slots/hooks/useSlotNodeNetworkIo/index.ts | 2 + .../useSlotNodeNetworkIo.ts | 35 + src/routes/ethereum/slots/$slot.tsx | 2 + 17 files changed, 5661 insertions(+), 29 deletions(-) create mode 100644 src/pages/ethereum/slots/components/NodeResources/DiskIoChart.tsx create mode 100644 src/pages/ethereum/slots/components/NodeResources/MemoryUsageChart.tsx create mode 100644 src/pages/ethereum/slots/components/NodeResources/NetworkIoChart.tsx create mode 100644 src/pages/ethereum/slots/hooks/useSlotNodeDiskIo/index.ts create mode 100644 src/pages/ethereum/slots/hooks/useSlotNodeDiskIo/useSlotNodeDiskIo.ts create mode 100644 src/pages/ethereum/slots/hooks/useSlotNodeMemory/index.ts create mode 100644 src/pages/ethereum/slots/hooks/useSlotNodeMemory/useSlotNodeMemory.ts create mode 100644 src/pages/ethereum/slots/hooks/useSlotNodeNetworkIo/index.ts create mode 100644 src/pages/ethereum/slots/hooks/useSlotNodeNetworkIo/useSlotNodeNetworkIo.ts diff --git a/src/api/@tanstack/react-query.gen.ts b/src/api/@tanstack/react-query.gen.ts index 95bdf7996..85cfa5f41 100644 --- a/src/api/@tanstack/react-query.gen.ts +++ b/src/api/@tanstack/react-query.gen.ts @@ -186,6 +186,12 @@ import { fctNodeActiveLast24hServiceList, fctNodeCpuUtilizationByProcessServiceGet, fctNodeCpuUtilizationByProcessServiceList, + fctNodeDiskIoByProcessServiceGet, + fctNodeDiskIoByProcessServiceList, + fctNodeMemoryUsageByProcessServiceGet, + fctNodeMemoryUsageByProcessServiceList, + fctNodeNetworkIoByProcessServiceGet, + fctNodeNetworkIoByProcessServiceList, fctOpcodeGasByOpcodeDailyServiceGet, fctOpcodeGasByOpcodeDailyServiceList, fctOpcodeGasByOpcodeHourlyServiceGet, @@ -909,6 +915,24 @@ import type { FctNodeCpuUtilizationByProcessServiceListData, FctNodeCpuUtilizationByProcessServiceListError, FctNodeCpuUtilizationByProcessServiceListResponse, + FctNodeDiskIoByProcessServiceGetData, + FctNodeDiskIoByProcessServiceGetError, + FctNodeDiskIoByProcessServiceGetResponse, + FctNodeDiskIoByProcessServiceListData, + FctNodeDiskIoByProcessServiceListError, + FctNodeDiskIoByProcessServiceListResponse, + FctNodeMemoryUsageByProcessServiceGetData, + FctNodeMemoryUsageByProcessServiceGetError, + FctNodeMemoryUsageByProcessServiceGetResponse, + FctNodeMemoryUsageByProcessServiceListData, + FctNodeMemoryUsageByProcessServiceListError, + FctNodeMemoryUsageByProcessServiceListResponse, + FctNodeNetworkIoByProcessServiceGetData, + FctNodeNetworkIoByProcessServiceGetError, + FctNodeNetworkIoByProcessServiceGetResponse, + FctNodeNetworkIoByProcessServiceListData, + FctNodeNetworkIoByProcessServiceListError, + FctNodeNetworkIoByProcessServiceListResponse, FctOpcodeGasByOpcodeDailyServiceGetData, FctOpcodeGasByOpcodeDailyServiceGetError, FctOpcodeGasByOpcodeDailyServiceGetResponse, @@ -6743,6 +6767,178 @@ export const fctNodeCpuUtilizationByProcessServiceGetOptions = ( queryKey: fctNodeCpuUtilizationByProcessServiceGetQueryKey(options), }); +export const fctNodeDiskIoByProcessServiceListQueryKey = (options?: Options) => + createQueryKey('fctNodeDiskIoByProcessServiceList', options); + +/** + * List records + * + * Retrieve paginated results with optional filtering + */ +export const fctNodeDiskIoByProcessServiceListOptions = (options?: Options) => + queryOptions< + FctNodeDiskIoByProcessServiceListResponse, + FctNodeDiskIoByProcessServiceListError, + FctNodeDiskIoByProcessServiceListResponse, + ReturnType + >({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await fctNodeDiskIoByProcessServiceList({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: fctNodeDiskIoByProcessServiceListQueryKey(options), + }); + +export const fctNodeDiskIoByProcessServiceGetQueryKey = (options: Options) => + createQueryKey('fctNodeDiskIoByProcessServiceGet', options); + +/** + * Get record + * + * Retrieve a single record by wallclock_slot_start_date_time + */ +export const fctNodeDiskIoByProcessServiceGetOptions = (options: Options) => + queryOptions< + FctNodeDiskIoByProcessServiceGetResponse, + FctNodeDiskIoByProcessServiceGetError, + FctNodeDiskIoByProcessServiceGetResponse, + ReturnType + >({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await fctNodeDiskIoByProcessServiceGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: fctNodeDiskIoByProcessServiceGetQueryKey(options), + }); + +export const fctNodeMemoryUsageByProcessServiceListQueryKey = ( + options?: Options +) => createQueryKey('fctNodeMemoryUsageByProcessServiceList', options); + +/** + * List records + * + * Retrieve paginated results with optional filtering + */ +export const fctNodeMemoryUsageByProcessServiceListOptions = ( + options?: Options +) => + queryOptions< + FctNodeMemoryUsageByProcessServiceListResponse, + FctNodeMemoryUsageByProcessServiceListError, + FctNodeMemoryUsageByProcessServiceListResponse, + ReturnType + >({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await fctNodeMemoryUsageByProcessServiceList({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: fctNodeMemoryUsageByProcessServiceListQueryKey(options), + }); + +export const fctNodeMemoryUsageByProcessServiceGetQueryKey = ( + options: Options +) => createQueryKey('fctNodeMemoryUsageByProcessServiceGet', options); + +/** + * Get record + * + * Retrieve a single record by wallclock_slot_start_date_time + */ +export const fctNodeMemoryUsageByProcessServiceGetOptions = ( + options: Options +) => + queryOptions< + FctNodeMemoryUsageByProcessServiceGetResponse, + FctNodeMemoryUsageByProcessServiceGetError, + FctNodeMemoryUsageByProcessServiceGetResponse, + ReturnType + >({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await fctNodeMemoryUsageByProcessServiceGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: fctNodeMemoryUsageByProcessServiceGetQueryKey(options), + }); + +export const fctNodeNetworkIoByProcessServiceListQueryKey = ( + options?: Options +) => createQueryKey('fctNodeNetworkIoByProcessServiceList', options); + +/** + * List records + * + * Retrieve paginated results with optional filtering + */ +export const fctNodeNetworkIoByProcessServiceListOptions = ( + options?: Options +) => + queryOptions< + FctNodeNetworkIoByProcessServiceListResponse, + FctNodeNetworkIoByProcessServiceListError, + FctNodeNetworkIoByProcessServiceListResponse, + ReturnType + >({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await fctNodeNetworkIoByProcessServiceList({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: fctNodeNetworkIoByProcessServiceListQueryKey(options), + }); + +export const fctNodeNetworkIoByProcessServiceGetQueryKey = ( + options: Options +) => createQueryKey('fctNodeNetworkIoByProcessServiceGet', options); + +/** + * Get record + * + * Retrieve a single record by wallclock_slot_start_date_time + */ +export const fctNodeNetworkIoByProcessServiceGetOptions = (options: Options) => + queryOptions< + FctNodeNetworkIoByProcessServiceGetResponse, + FctNodeNetworkIoByProcessServiceGetError, + FctNodeNetworkIoByProcessServiceGetResponse, + ReturnType + >({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await fctNodeNetworkIoByProcessServiceGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: fctNodeNetworkIoByProcessServiceGetQueryKey(options), + }); + export const fctOpcodeGasByOpcodeDailyServiceListQueryKey = ( options?: Options ) => createQueryKey('fctOpcodeGasByOpcodeDailyServiceList', options); diff --git a/src/api/index.ts b/src/api/index.ts index d9b954203..2b5fe6a57 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -183,6 +183,12 @@ export { fctNodeActiveLast24hServiceList, fctNodeCpuUtilizationByProcessServiceGet, fctNodeCpuUtilizationByProcessServiceList, + fctNodeDiskIoByProcessServiceGet, + fctNodeDiskIoByProcessServiceList, + fctNodeMemoryUsageByProcessServiceGet, + fctNodeMemoryUsageByProcessServiceList, + fctNodeNetworkIoByProcessServiceGet, + fctNodeNetworkIoByProcessServiceList, fctOpcodeGasByOpcodeDailyServiceGet, fctOpcodeGasByOpcodeDailyServiceList, fctOpcodeGasByOpcodeHourlyServiceGet, @@ -1362,6 +1368,39 @@ export type { FctNodeCpuUtilizationByProcessServiceListErrors, FctNodeCpuUtilizationByProcessServiceListResponse, FctNodeCpuUtilizationByProcessServiceListResponses, + FctNodeDiskIoByProcess, + FctNodeDiskIoByProcessServiceGetData, + FctNodeDiskIoByProcessServiceGetError, + FctNodeDiskIoByProcessServiceGetErrors, + FctNodeDiskIoByProcessServiceGetResponse, + FctNodeDiskIoByProcessServiceGetResponses, + FctNodeDiskIoByProcessServiceListData, + FctNodeDiskIoByProcessServiceListError, + FctNodeDiskIoByProcessServiceListErrors, + FctNodeDiskIoByProcessServiceListResponse, + FctNodeDiskIoByProcessServiceListResponses, + FctNodeMemoryUsageByProcess, + FctNodeMemoryUsageByProcessServiceGetData, + FctNodeMemoryUsageByProcessServiceGetError, + FctNodeMemoryUsageByProcessServiceGetErrors, + FctNodeMemoryUsageByProcessServiceGetResponse, + FctNodeMemoryUsageByProcessServiceGetResponses, + FctNodeMemoryUsageByProcessServiceListData, + FctNodeMemoryUsageByProcessServiceListError, + FctNodeMemoryUsageByProcessServiceListErrors, + FctNodeMemoryUsageByProcessServiceListResponse, + FctNodeMemoryUsageByProcessServiceListResponses, + FctNodeNetworkIoByProcess, + FctNodeNetworkIoByProcessServiceGetData, + FctNodeNetworkIoByProcessServiceGetError, + FctNodeNetworkIoByProcessServiceGetErrors, + FctNodeNetworkIoByProcessServiceGetResponse, + FctNodeNetworkIoByProcessServiceGetResponses, + FctNodeNetworkIoByProcessServiceListData, + FctNodeNetworkIoByProcessServiceListError, + FctNodeNetworkIoByProcessServiceListErrors, + FctNodeNetworkIoByProcessServiceListResponse, + FctNodeNetworkIoByProcessServiceListResponses, FctOpcodeGasByOpcodeDaily, FctOpcodeGasByOpcodeDailyServiceGetData, FctOpcodeGasByOpcodeDailyServiceGetError, @@ -1728,6 +1767,9 @@ export type { GetFctMissedSlotRateHourlyResponse, GetFctNodeActiveLast24hResponse, GetFctNodeCpuUtilizationByProcessResponse, + GetFctNodeDiskIoByProcessResponse, + GetFctNodeMemoryUsageByProcessResponse, + GetFctNodeNetworkIoByProcessResponse, GetFctOpcodeGasByOpcodeDailyResponse, GetFctOpcodeGasByOpcodeHourlyResponse, GetFctOpcodeOpsDailyResponse, @@ -2589,6 +2631,9 @@ export type { ListFctMissedSlotRateHourlyResponse, ListFctNodeActiveLast24hResponse, ListFctNodeCpuUtilizationByProcessResponse, + ListFctNodeDiskIoByProcessResponse, + ListFctNodeMemoryUsageByProcessResponse, + ListFctNodeNetworkIoByProcessResponse, ListFctOpcodeGasByOpcodeDailyResponse, ListFctOpcodeGasByOpcodeHourlyResponse, ListFctOpcodeOpsDailyResponse, diff --git a/src/api/sdk.gen.ts b/src/api/sdk.gen.ts index 7344d3794..e9e957f1e 100644 --- a/src/api/sdk.gen.ts +++ b/src/api/sdk.gen.ts @@ -549,6 +549,24 @@ import type { FctNodeCpuUtilizationByProcessServiceListData, FctNodeCpuUtilizationByProcessServiceListErrors, FctNodeCpuUtilizationByProcessServiceListResponses, + FctNodeDiskIoByProcessServiceGetData, + FctNodeDiskIoByProcessServiceGetErrors, + FctNodeDiskIoByProcessServiceGetResponses, + FctNodeDiskIoByProcessServiceListData, + FctNodeDiskIoByProcessServiceListErrors, + FctNodeDiskIoByProcessServiceListResponses, + FctNodeMemoryUsageByProcessServiceGetData, + FctNodeMemoryUsageByProcessServiceGetErrors, + FctNodeMemoryUsageByProcessServiceGetResponses, + FctNodeMemoryUsageByProcessServiceListData, + FctNodeMemoryUsageByProcessServiceListErrors, + FctNodeMemoryUsageByProcessServiceListResponses, + FctNodeNetworkIoByProcessServiceGetData, + FctNodeNetworkIoByProcessServiceGetErrors, + FctNodeNetworkIoByProcessServiceGetResponses, + FctNodeNetworkIoByProcessServiceListData, + FctNodeNetworkIoByProcessServiceListErrors, + FctNodeNetworkIoByProcessServiceListResponses, FctOpcodeGasByOpcodeDailyServiceGetData, FctOpcodeGasByOpcodeDailyServiceGetErrors, FctOpcodeGasByOpcodeDailyServiceGetResponses, @@ -1437,6 +1455,18 @@ import { zFctNodeCpuUtilizationByProcessServiceGetResponse, zFctNodeCpuUtilizationByProcessServiceListData, zFctNodeCpuUtilizationByProcessServiceListResponse, + zFctNodeDiskIoByProcessServiceGetData, + zFctNodeDiskIoByProcessServiceGetResponse, + zFctNodeDiskIoByProcessServiceListData, + zFctNodeDiskIoByProcessServiceListResponse, + zFctNodeMemoryUsageByProcessServiceGetData, + zFctNodeMemoryUsageByProcessServiceGetResponse, + zFctNodeMemoryUsageByProcessServiceListData, + zFctNodeMemoryUsageByProcessServiceListResponse, + zFctNodeNetworkIoByProcessServiceGetData, + zFctNodeNetworkIoByProcessServiceGetResponse, + zFctNodeNetworkIoByProcessServiceListData, + zFctNodeNetworkIoByProcessServiceListResponse, zFctOpcodeGasByOpcodeDailyServiceGetData, zFctOpcodeGasByOpcodeDailyServiceGetResponse, zFctOpcodeGasByOpcodeDailyServiceListData, @@ -5240,6 +5270,120 @@ export const fctNodeCpuUtilizationByProcessServiceGet = ( + options?: Options +) => + (options?.client ?? client).get< + FctNodeDiskIoByProcessServiceListResponses, + FctNodeDiskIoByProcessServiceListErrors, + ThrowOnError + >({ + requestValidator: async data => await zFctNodeDiskIoByProcessServiceListData.parseAsync(data), + responseValidator: async data => await zFctNodeDiskIoByProcessServiceListResponse.parseAsync(data), + url: '/api/v1/fct_node_disk_io_by_process', + ...options, + }); + +/** + * Get record + * + * Retrieve a single record by wallclock_slot_start_date_time + */ +export const fctNodeDiskIoByProcessServiceGet = ( + options: Options +) => + (options.client ?? client).get< + FctNodeDiskIoByProcessServiceGetResponses, + FctNodeDiskIoByProcessServiceGetErrors, + ThrowOnError + >({ + requestValidator: async data => await zFctNodeDiskIoByProcessServiceGetData.parseAsync(data), + responseValidator: async data => await zFctNodeDiskIoByProcessServiceGetResponse.parseAsync(data), + url: '/api/v1/fct_node_disk_io_by_process/{wallclock_slot_start_date_time}', + ...options, + }); + +/** + * List records + * + * Retrieve paginated results with optional filtering + */ +export const fctNodeMemoryUsageByProcessServiceList = ( + options?: Options +) => + (options?.client ?? client).get< + FctNodeMemoryUsageByProcessServiceListResponses, + FctNodeMemoryUsageByProcessServiceListErrors, + ThrowOnError + >({ + requestValidator: async data => await zFctNodeMemoryUsageByProcessServiceListData.parseAsync(data), + responseValidator: async data => await zFctNodeMemoryUsageByProcessServiceListResponse.parseAsync(data), + url: '/api/v1/fct_node_memory_usage_by_process', + ...options, + }); + +/** + * Get record + * + * Retrieve a single record by wallclock_slot_start_date_time + */ +export const fctNodeMemoryUsageByProcessServiceGet = ( + options: Options +) => + (options.client ?? client).get< + FctNodeMemoryUsageByProcessServiceGetResponses, + FctNodeMemoryUsageByProcessServiceGetErrors, + ThrowOnError + >({ + requestValidator: async data => await zFctNodeMemoryUsageByProcessServiceGetData.parseAsync(data), + responseValidator: async data => await zFctNodeMemoryUsageByProcessServiceGetResponse.parseAsync(data), + url: '/api/v1/fct_node_memory_usage_by_process/{wallclock_slot_start_date_time}', + ...options, + }); + +/** + * List records + * + * Retrieve paginated results with optional filtering + */ +export const fctNodeNetworkIoByProcessServiceList = ( + options?: Options +) => + (options?.client ?? client).get< + FctNodeNetworkIoByProcessServiceListResponses, + FctNodeNetworkIoByProcessServiceListErrors, + ThrowOnError + >({ + requestValidator: async data => await zFctNodeNetworkIoByProcessServiceListData.parseAsync(data), + responseValidator: async data => await zFctNodeNetworkIoByProcessServiceListResponse.parseAsync(data), + url: '/api/v1/fct_node_network_io_by_process', + ...options, + }); + +/** + * Get record + * + * Retrieve a single record by wallclock_slot_start_date_time + */ +export const fctNodeNetworkIoByProcessServiceGet = ( + options: Options +) => + (options.client ?? client).get< + FctNodeNetworkIoByProcessServiceGetResponses, + FctNodeNetworkIoByProcessServiceGetErrors, + ThrowOnError + >({ + requestValidator: async data => await zFctNodeNetworkIoByProcessServiceGetData.parseAsync(data), + responseValidator: async data => await zFctNodeNetworkIoByProcessServiceGetResponse.parseAsync(data), + url: '/api/v1/fct_node_network_io_by_process/{wallclock_slot_start_date_time}', + ...options, + }); + /** * List records * diff --git a/src/api/types.gen.ts b/src/api/types.gen.ts index 3cdab65f7..3e5dcd1aa 100644 --- a/src/api/types.gen.ts +++ b/src/api/types.gen.ts @@ -4615,6 +4615,167 @@ export type FctNodeCpuUtilizationByProcess = { window_start?: number; }; +export type FctNodeDiskIoByProcess = { + /** + * Client type: CL or EL + */ + client_type?: string; + /** + * Total bytes transferred across all devices in this window + */ + io_bytes?: number; + /** + * Total I/O operations across all devices in this window + */ + io_ops?: number; + /** + * Name of the observoor client that collected the data + */ + meta_client_name?: string; + /** + * Ethereum network name + */ + meta_network_name?: string; + /** + * Node classification for filtering (e.g. eip7870) + */ + node_class?: string; + /** + * Process ID of the monitored client + */ + pid?: number; + /** + * I/O direction: read or write + */ + rw?: string; + /** + * Timestamp when the record was last updated + */ + updated_date_time?: number; + /** + * The wallclock slot number + */ + wallclock_slot?: number; + /** + * The wall clock time when the slot started + */ + wallclock_slot_start_date_time?: number; + /** + * Start of the sub-slot aggregation window + */ + window_start?: number; +}; + +export type FctNodeMemoryUsageByProcess = { + /** + * Client type: CL or EL + */ + client_type?: string; + /** + * Name of the observoor client that collected the data + */ + meta_client_name?: string; + /** + * Ethereum network name + */ + meta_network_name?: string; + /** + * Node classification for filtering (e.g. eip7870) + */ + node_class?: string; + /** + * Process ID of the monitored client + */ + pid?: number; + /** + * Anonymous RSS in bytes (heap, stack, anonymous mmap) + */ + rss_anon_bytes?: number; + /** + * File-backed RSS in bytes (shared libraries, mmap files) + */ + rss_file_bytes?: number; + /** + * Timestamp when the record was last updated + */ + updated_date_time?: number; + /** + * Resident set size in bytes (total physical memory used) + */ + vm_rss_bytes?: number; + /** + * Swap usage in bytes + */ + vm_swap_bytes?: number; + /** + * The wallclock slot number + */ + wallclock_slot?: number; + /** + * The wall clock time when the slot started + */ + wallclock_slot_start_date_time?: number; + /** + * Start of the sub-slot aggregation window + */ + window_start?: number; +}; + +export type FctNodeNetworkIoByProcess = { + /** + * Client type: CL or EL + */ + client_type?: string; + /** + * Traffic direction: tx or rx + */ + direction?: string; + /** + * Total bytes transferred in this window + */ + io_bytes?: number; + /** + * Total packet or event count in this window + */ + io_count?: number; + /** + * Name of the observoor client that collected the data + */ + meta_client_name?: string; + /** + * Ethereum network name + */ + meta_network_name?: string; + /** + * Node classification for filtering (e.g. eip7870) + */ + node_class?: string; + /** + * Process ID of the monitored client + */ + pid?: number; + /** + * Port classification (e.g. cl_p2p_tcp, el_json_rpc, unknown) + */ + port_label?: string; + /** + * Timestamp when the record was last updated + */ + updated_date_time?: number; + /** + * The wallclock slot number + */ + wallclock_slot?: number; + /** + * The wall clock time when the slot started + */ + wallclock_slot_start_date_time?: number; + /** + * Start of the sub-slot aggregation window + */ + window_start?: number; +}; + export type FctOpcodeGasByOpcodeDaily = { /** * Average executions per block @@ -6211,6 +6372,27 @@ export type GetFctNodeCpuUtilizationByProcessResponse = { item?: FctNodeCpuUtilizationByProcess; }; +/** + * Response for getting a single fct_node_disk_io_by_process record + */ +export type GetFctNodeDiskIoByProcessResponse = { + item?: FctNodeDiskIoByProcess; +}; + +/** + * Response for getting a single fct_node_memory_usage_by_process record + */ +export type GetFctNodeMemoryUsageByProcessResponse = { + item?: FctNodeMemoryUsageByProcess; +}; + +/** + * Response for getting a single fct_node_network_io_by_process record + */ +export type GetFctNodeNetworkIoByProcessResponse = { + item?: FctNodeNetworkIoByProcess; +}; + /** * Response for getting a single fct_opcode_gas_by_opcode_daily record */ @@ -10715,6 +10897,48 @@ export type ListFctNodeCpuUtilizationByProcessResponse = { next_page_token?: string; }; +/** + * Response for listing fct_node_disk_io_by_process records + */ +export type ListFctNodeDiskIoByProcessResponse = { + /** + * The list of fct_node_disk_io_by_process. + */ + fct_node_disk_io_by_process?: Array; + /** + * A token, which can be sent as `page_token` to retrieve the next page. If this field is omitted, there are no subsequent pages. + */ + next_page_token?: string; +}; + +/** + * Response for listing fct_node_memory_usage_by_process records + */ +export type ListFctNodeMemoryUsageByProcessResponse = { + /** + * The list of fct_node_memory_usage_by_process. + */ + fct_node_memory_usage_by_process?: Array; + /** + * A token, which can be sent as `page_token` to retrieve the next page. If this field is omitted, there are no subsequent pages. + */ + next_page_token?: string; +}; + +/** + * Response for listing fct_node_network_io_by_process records + */ +export type ListFctNodeNetworkIoByProcessResponse = { + /** + * The list of fct_node_network_io_by_process. + */ + fct_node_network_io_by_process?: Array; + /** + * A token, which can be sent as `page_token` to retrieve the next page. If this field is omitted, there are no subsequent pages. + */ + next_page_token?: string; +}; + /** * Response for listing fct_opcode_gas_by_opcode_daily records */ @@ -55569,6 +55793,1610 @@ export type FctNodeCpuUtilizationByProcessServiceGetResponses = { export type FctNodeCpuUtilizationByProcessServiceGetResponse = FctNodeCpuUtilizationByProcessServiceGetResponses[keyof FctNodeCpuUtilizationByProcessServiceGetResponses]; +export type FctNodeDiskIoByProcessServiceListData = { + body?: never; + path?: never; + query?: { + /** + * The wall clock time when the slot started (filter: eq) + */ + wallclock_slot_start_date_time_eq?: number; + /** + * The wall clock time when the slot started (filter: ne) + */ + wallclock_slot_start_date_time_ne?: number; + /** + * The wall clock time when the slot started (filter: lt) + */ + wallclock_slot_start_date_time_lt?: number; + /** + * The wall clock time when the slot started (filter: lte) + */ + wallclock_slot_start_date_time_lte?: number; + /** + * The wall clock time when the slot started (filter: gt) + */ + wallclock_slot_start_date_time_gt?: number; + /** + * The wall clock time when the slot started (filter: gte) + */ + wallclock_slot_start_date_time_gte?: number; + /** + * The wall clock time when the slot started (filter: between_min) + */ + wallclock_slot_start_date_time_between_min?: number; + /** + * The wall clock time when the slot started (filter: between_max_value) + */ + wallclock_slot_start_date_time_between_max_value?: number; + /** + * The wall clock time when the slot started (filter: in_values) (comma-separated list) + */ + wallclock_slot_start_date_time_in_values?: string; + /** + * The wall clock time when the slot started (filter: not_in_values) (comma-separated list) + */ + wallclock_slot_start_date_time_not_in_values?: string; + /** + * Name of the observoor client that collected the data (filter: eq) + */ + meta_client_name_eq?: string; + /** + * Name of the observoor client that collected the data (filter: ne) + */ + meta_client_name_ne?: string; + /** + * Name of the observoor client that collected the data (filter: contains) + */ + meta_client_name_contains?: string; + /** + * Name of the observoor client that collected the data (filter: starts_with) + */ + meta_client_name_starts_with?: string; + /** + * Name of the observoor client that collected the data (filter: ends_with) + */ + meta_client_name_ends_with?: string; + /** + * Name of the observoor client that collected the data (filter: like) + */ + meta_client_name_like?: string; + /** + * Name of the observoor client that collected the data (filter: not_like) + */ + meta_client_name_not_like?: string; + /** + * Name of the observoor client that collected the data (filter: in_values) (comma-separated list) + */ + meta_client_name_in_values?: string; + /** + * Name of the observoor client that collected the data (filter: not_in_values) (comma-separated list) + */ + meta_client_name_not_in_values?: string; + /** + * Client type: CL or EL (filter: eq) + */ + client_type_eq?: string; + /** + * Client type: CL or EL (filter: ne) + */ + client_type_ne?: string; + /** + * Client type: CL or EL (filter: contains) + */ + client_type_contains?: string; + /** + * Client type: CL or EL (filter: starts_with) + */ + client_type_starts_with?: string; + /** + * Client type: CL or EL (filter: ends_with) + */ + client_type_ends_with?: string; + /** + * Client type: CL or EL (filter: like) + */ + client_type_like?: string; + /** + * Client type: CL or EL (filter: not_like) + */ + client_type_not_like?: string; + /** + * Client type: CL or EL (filter: in_values) (comma-separated list) + */ + client_type_in_values?: string; + /** + * Client type: CL or EL (filter: not_in_values) (comma-separated list) + */ + client_type_not_in_values?: string; + /** + * Process ID of the monitored client (filter: eq) + */ + pid_eq?: number; + /** + * Process ID of the monitored client (filter: ne) + */ + pid_ne?: number; + /** + * Process ID of the monitored client (filter: lt) + */ + pid_lt?: number; + /** + * Process ID of the monitored client (filter: lte) + */ + pid_lte?: number; + /** + * Process ID of the monitored client (filter: gt) + */ + pid_gt?: number; + /** + * Process ID of the monitored client (filter: gte) + */ + pid_gte?: number; + /** + * Process ID of the monitored client (filter: between_min) + */ + pid_between_min?: number; + /** + * Process ID of the monitored client (filter: between_max_value) + */ + pid_between_max_value?: number; + /** + * Process ID of the monitored client (filter: in_values) (comma-separated list) + */ + pid_in_values?: string; + /** + * Process ID of the monitored client (filter: not_in_values) (comma-separated list) + */ + pid_not_in_values?: string; + /** + * I/O direction: read or write (filter: eq) + */ + rw_eq?: string; + /** + * I/O direction: read or write (filter: ne) + */ + rw_ne?: string; + /** + * I/O direction: read or write (filter: contains) + */ + rw_contains?: string; + /** + * I/O direction: read or write (filter: starts_with) + */ + rw_starts_with?: string; + /** + * I/O direction: read or write (filter: ends_with) + */ + rw_ends_with?: string; + /** + * I/O direction: read or write (filter: like) + */ + rw_like?: string; + /** + * I/O direction: read or write (filter: not_like) + */ + rw_not_like?: string; + /** + * I/O direction: read or write (filter: in_values) (comma-separated list) + */ + rw_in_values?: string; + /** + * I/O direction: read or write (filter: not_in_values) (comma-separated list) + */ + rw_not_in_values?: string; + /** + * Start of the sub-slot aggregation window (filter: eq) + */ + window_start_eq?: number; + /** + * Start of the sub-slot aggregation window (filter: ne) + */ + window_start_ne?: number; + /** + * Start of the sub-slot aggregation window (filter: lt) + */ + window_start_lt?: number; + /** + * Start of the sub-slot aggregation window (filter: lte) + */ + window_start_lte?: number; + /** + * Start of the sub-slot aggregation window (filter: gt) + */ + window_start_gt?: number; + /** + * Start of the sub-slot aggregation window (filter: gte) + */ + window_start_gte?: number; + /** + * Start of the sub-slot aggregation window (filter: between_min) + */ + window_start_between_min?: number; + /** + * Start of the sub-slot aggregation window (filter: between_max_value) + */ + window_start_between_max_value?: number; + /** + * Start of the sub-slot aggregation window (filter: in_values) (comma-separated list) + */ + window_start_in_values?: string; + /** + * Start of the sub-slot aggregation window (filter: not_in_values) (comma-separated list) + */ + window_start_not_in_values?: string; + /** + * Timestamp when the record was last updated (filter: eq) + */ + updated_date_time_eq?: number; + /** + * Timestamp when the record was last updated (filter: ne) + */ + updated_date_time_ne?: number; + /** + * Timestamp when the record was last updated (filter: lt) + */ + updated_date_time_lt?: number; + /** + * Timestamp when the record was last updated (filter: lte) + */ + updated_date_time_lte?: number; + /** + * Timestamp when the record was last updated (filter: gt) + */ + updated_date_time_gt?: number; + /** + * Timestamp when the record was last updated (filter: gte) + */ + updated_date_time_gte?: number; + /** + * Timestamp when the record was last updated (filter: between_min) + */ + updated_date_time_between_min?: number; + /** + * Timestamp when the record was last updated (filter: between_max_value) + */ + updated_date_time_between_max_value?: number; + /** + * Timestamp when the record was last updated (filter: in_values) (comma-separated list) + */ + updated_date_time_in_values?: string; + /** + * Timestamp when the record was last updated (filter: not_in_values) (comma-separated list) + */ + updated_date_time_not_in_values?: string; + /** + * The wallclock slot number (filter: eq) + */ + wallclock_slot_eq?: number; + /** + * The wallclock slot number (filter: ne) + */ + wallclock_slot_ne?: number; + /** + * The wallclock slot number (filter: lt) + */ + wallclock_slot_lt?: number; + /** + * The wallclock slot number (filter: lte) + */ + wallclock_slot_lte?: number; + /** + * The wallclock slot number (filter: gt) + */ + wallclock_slot_gt?: number; + /** + * The wallclock slot number (filter: gte) + */ + wallclock_slot_gte?: number; + /** + * The wallclock slot number (filter: between_min) + */ + wallclock_slot_between_min?: number; + /** + * The wallclock slot number (filter: between_max_value) + */ + wallclock_slot_between_max_value?: number; + /** + * The wallclock slot number (filter: in_values) (comma-separated list) + */ + wallclock_slot_in_values?: string; + /** + * The wallclock slot number (filter: not_in_values) (comma-separated list) + */ + wallclock_slot_not_in_values?: string; + /** + * Ethereum network name (filter: eq) + */ + meta_network_name_eq?: string; + /** + * Ethereum network name (filter: ne) + */ + meta_network_name_ne?: string; + /** + * Ethereum network name (filter: contains) + */ + meta_network_name_contains?: string; + /** + * Ethereum network name (filter: starts_with) + */ + meta_network_name_starts_with?: string; + /** + * Ethereum network name (filter: ends_with) + */ + meta_network_name_ends_with?: string; + /** + * Ethereum network name (filter: like) + */ + meta_network_name_like?: string; + /** + * Ethereum network name (filter: not_like) + */ + meta_network_name_not_like?: string; + /** + * Ethereum network name (filter: in_values) (comma-separated list) + */ + meta_network_name_in_values?: string; + /** + * Ethereum network name (filter: not_in_values) (comma-separated list) + */ + meta_network_name_not_in_values?: string; + /** + * Filter io_bytes using value + */ + io_bytes_value?: number; + /** + * Total I/O operations across all devices in this window (filter: eq) + */ + io_ops_eq?: number; + /** + * Total I/O operations across all devices in this window (filter: ne) + */ + io_ops_ne?: number; + /** + * Total I/O operations across all devices in this window (filter: lt) + */ + io_ops_lt?: number; + /** + * Total I/O operations across all devices in this window (filter: lte) + */ + io_ops_lte?: number; + /** + * Total I/O operations across all devices in this window (filter: gt) + */ + io_ops_gt?: number; + /** + * Total I/O operations across all devices in this window (filter: gte) + */ + io_ops_gte?: number; + /** + * Total I/O operations across all devices in this window (filter: between_min) + */ + io_ops_between_min?: number; + /** + * Total I/O operations across all devices in this window (filter: between_max_value) + */ + io_ops_between_max_value?: number; + /** + * Total I/O operations across all devices in this window (filter: in_values) (comma-separated list) + */ + io_ops_in_values?: string; + /** + * Total I/O operations across all devices in this window (filter: not_in_values) (comma-separated list) + */ + io_ops_not_in_values?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: eq) + */ + node_class_eq?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: ne) + */ + node_class_ne?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: contains) + */ + node_class_contains?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: starts_with) + */ + node_class_starts_with?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: ends_with) + */ + node_class_ends_with?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: like) + */ + node_class_like?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: not_like) + */ + node_class_not_like?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: in_values) (comma-separated list) + */ + node_class_in_values?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: not_in_values) (comma-separated list) + */ + node_class_not_in_values?: string; + /** + * The maximum number of fct_node_disk_io_by_process to return. If unspecified, at most 100 items will be returned. The maximum value is 10000; values above 10000 will be coerced to 10000. + */ + page_size?: number; + /** + * A page token, received from a previous `ListFctNodeDiskIoByProcess` call. Provide this to retrieve the subsequent page. + */ + page_token?: string; + /** + * The order of results. Format: comma-separated list of fields. Example: "foo,bar" or "foo desc,bar" for descending order on foo. If unspecified, results will be returned in the default order. + */ + order_by?: string; + }; + url: '/api/v1/fct_node_disk_io_by_process'; +}; + +export type FctNodeDiskIoByProcessServiceListErrors = { + /** + * Default error response + */ + default: Status; +}; + +export type FctNodeDiskIoByProcessServiceListError = + FctNodeDiskIoByProcessServiceListErrors[keyof FctNodeDiskIoByProcessServiceListErrors]; + +export type FctNodeDiskIoByProcessServiceListResponses = { + /** + * OK + */ + 200: ListFctNodeDiskIoByProcessResponse; +}; + +export type FctNodeDiskIoByProcessServiceListResponse = + FctNodeDiskIoByProcessServiceListResponses[keyof FctNodeDiskIoByProcessServiceListResponses]; + +export type FctNodeDiskIoByProcessServiceGetData = { + body?: never; + path: { + /** + * The wall clock time when the slot started + */ + wallclock_slot_start_date_time: number; + }; + query?: never; + url: '/api/v1/fct_node_disk_io_by_process/{wallclock_slot_start_date_time}'; +}; + +export type FctNodeDiskIoByProcessServiceGetErrors = { + /** + * Default error response + */ + default: Status; +}; + +export type FctNodeDiskIoByProcessServiceGetError = + FctNodeDiskIoByProcessServiceGetErrors[keyof FctNodeDiskIoByProcessServiceGetErrors]; + +export type FctNodeDiskIoByProcessServiceGetResponses = { + /** + * OK + */ + 200: GetFctNodeDiskIoByProcessResponse; +}; + +export type FctNodeDiskIoByProcessServiceGetResponse = + FctNodeDiskIoByProcessServiceGetResponses[keyof FctNodeDiskIoByProcessServiceGetResponses]; + +export type FctNodeMemoryUsageByProcessServiceListData = { + body?: never; + path?: never; + query?: { + /** + * The wall clock time when the slot started (filter: eq) + */ + wallclock_slot_start_date_time_eq?: number; + /** + * The wall clock time when the slot started (filter: ne) + */ + wallclock_slot_start_date_time_ne?: number; + /** + * The wall clock time when the slot started (filter: lt) + */ + wallclock_slot_start_date_time_lt?: number; + /** + * The wall clock time when the slot started (filter: lte) + */ + wallclock_slot_start_date_time_lte?: number; + /** + * The wall clock time when the slot started (filter: gt) + */ + wallclock_slot_start_date_time_gt?: number; + /** + * The wall clock time when the slot started (filter: gte) + */ + wallclock_slot_start_date_time_gte?: number; + /** + * The wall clock time when the slot started (filter: between_min) + */ + wallclock_slot_start_date_time_between_min?: number; + /** + * The wall clock time when the slot started (filter: between_max_value) + */ + wallclock_slot_start_date_time_between_max_value?: number; + /** + * The wall clock time when the slot started (filter: in_values) (comma-separated list) + */ + wallclock_slot_start_date_time_in_values?: string; + /** + * The wall clock time when the slot started (filter: not_in_values) (comma-separated list) + */ + wallclock_slot_start_date_time_not_in_values?: string; + /** + * Name of the observoor client that collected the data (filter: eq) + */ + meta_client_name_eq?: string; + /** + * Name of the observoor client that collected the data (filter: ne) + */ + meta_client_name_ne?: string; + /** + * Name of the observoor client that collected the data (filter: contains) + */ + meta_client_name_contains?: string; + /** + * Name of the observoor client that collected the data (filter: starts_with) + */ + meta_client_name_starts_with?: string; + /** + * Name of the observoor client that collected the data (filter: ends_with) + */ + meta_client_name_ends_with?: string; + /** + * Name of the observoor client that collected the data (filter: like) + */ + meta_client_name_like?: string; + /** + * Name of the observoor client that collected the data (filter: not_like) + */ + meta_client_name_not_like?: string; + /** + * Name of the observoor client that collected the data (filter: in_values) (comma-separated list) + */ + meta_client_name_in_values?: string; + /** + * Name of the observoor client that collected the data (filter: not_in_values) (comma-separated list) + */ + meta_client_name_not_in_values?: string; + /** + * Client type: CL or EL (filter: eq) + */ + client_type_eq?: string; + /** + * Client type: CL or EL (filter: ne) + */ + client_type_ne?: string; + /** + * Client type: CL or EL (filter: contains) + */ + client_type_contains?: string; + /** + * Client type: CL or EL (filter: starts_with) + */ + client_type_starts_with?: string; + /** + * Client type: CL or EL (filter: ends_with) + */ + client_type_ends_with?: string; + /** + * Client type: CL or EL (filter: like) + */ + client_type_like?: string; + /** + * Client type: CL or EL (filter: not_like) + */ + client_type_not_like?: string; + /** + * Client type: CL or EL (filter: in_values) (comma-separated list) + */ + client_type_in_values?: string; + /** + * Client type: CL or EL (filter: not_in_values) (comma-separated list) + */ + client_type_not_in_values?: string; + /** + * Process ID of the monitored client (filter: eq) + */ + pid_eq?: number; + /** + * Process ID of the monitored client (filter: ne) + */ + pid_ne?: number; + /** + * Process ID of the monitored client (filter: lt) + */ + pid_lt?: number; + /** + * Process ID of the monitored client (filter: lte) + */ + pid_lte?: number; + /** + * Process ID of the monitored client (filter: gt) + */ + pid_gt?: number; + /** + * Process ID of the monitored client (filter: gte) + */ + pid_gte?: number; + /** + * Process ID of the monitored client (filter: between_min) + */ + pid_between_min?: number; + /** + * Process ID of the monitored client (filter: between_max_value) + */ + pid_between_max_value?: number; + /** + * Process ID of the monitored client (filter: in_values) (comma-separated list) + */ + pid_in_values?: string; + /** + * Process ID of the monitored client (filter: not_in_values) (comma-separated list) + */ + pid_not_in_values?: string; + /** + * Start of the sub-slot aggregation window (filter: eq) + */ + window_start_eq?: number; + /** + * Start of the sub-slot aggregation window (filter: ne) + */ + window_start_ne?: number; + /** + * Start of the sub-slot aggregation window (filter: lt) + */ + window_start_lt?: number; + /** + * Start of the sub-slot aggregation window (filter: lte) + */ + window_start_lte?: number; + /** + * Start of the sub-slot aggregation window (filter: gt) + */ + window_start_gt?: number; + /** + * Start of the sub-slot aggregation window (filter: gte) + */ + window_start_gte?: number; + /** + * Start of the sub-slot aggregation window (filter: between_min) + */ + window_start_between_min?: number; + /** + * Start of the sub-slot aggregation window (filter: between_max_value) + */ + window_start_between_max_value?: number; + /** + * Start of the sub-slot aggregation window (filter: in_values) (comma-separated list) + */ + window_start_in_values?: string; + /** + * Start of the sub-slot aggregation window (filter: not_in_values) (comma-separated list) + */ + window_start_not_in_values?: string; + /** + * Timestamp when the record was last updated (filter: eq) + */ + updated_date_time_eq?: number; + /** + * Timestamp when the record was last updated (filter: ne) + */ + updated_date_time_ne?: number; + /** + * Timestamp when the record was last updated (filter: lt) + */ + updated_date_time_lt?: number; + /** + * Timestamp when the record was last updated (filter: lte) + */ + updated_date_time_lte?: number; + /** + * Timestamp when the record was last updated (filter: gt) + */ + updated_date_time_gt?: number; + /** + * Timestamp when the record was last updated (filter: gte) + */ + updated_date_time_gte?: number; + /** + * Timestamp when the record was last updated (filter: between_min) + */ + updated_date_time_between_min?: number; + /** + * Timestamp when the record was last updated (filter: between_max_value) + */ + updated_date_time_between_max_value?: number; + /** + * Timestamp when the record was last updated (filter: in_values) (comma-separated list) + */ + updated_date_time_in_values?: string; + /** + * Timestamp when the record was last updated (filter: not_in_values) (comma-separated list) + */ + updated_date_time_not_in_values?: string; + /** + * The wallclock slot number (filter: eq) + */ + wallclock_slot_eq?: number; + /** + * The wallclock slot number (filter: ne) + */ + wallclock_slot_ne?: number; + /** + * The wallclock slot number (filter: lt) + */ + wallclock_slot_lt?: number; + /** + * The wallclock slot number (filter: lte) + */ + wallclock_slot_lte?: number; + /** + * The wallclock slot number (filter: gt) + */ + wallclock_slot_gt?: number; + /** + * The wallclock slot number (filter: gte) + */ + wallclock_slot_gte?: number; + /** + * The wallclock slot number (filter: between_min) + */ + wallclock_slot_between_min?: number; + /** + * The wallclock slot number (filter: between_max_value) + */ + wallclock_slot_between_max_value?: number; + /** + * The wallclock slot number (filter: in_values) (comma-separated list) + */ + wallclock_slot_in_values?: string; + /** + * The wallclock slot number (filter: not_in_values) (comma-separated list) + */ + wallclock_slot_not_in_values?: string; + /** + * Ethereum network name (filter: eq) + */ + meta_network_name_eq?: string; + /** + * Ethereum network name (filter: ne) + */ + meta_network_name_ne?: string; + /** + * Ethereum network name (filter: contains) + */ + meta_network_name_contains?: string; + /** + * Ethereum network name (filter: starts_with) + */ + meta_network_name_starts_with?: string; + /** + * Ethereum network name (filter: ends_with) + */ + meta_network_name_ends_with?: string; + /** + * Ethereum network name (filter: like) + */ + meta_network_name_like?: string; + /** + * Ethereum network name (filter: not_like) + */ + meta_network_name_not_like?: string; + /** + * Ethereum network name (filter: in_values) (comma-separated list) + */ + meta_network_name_in_values?: string; + /** + * Ethereum network name (filter: not_in_values) (comma-separated list) + */ + meta_network_name_not_in_values?: string; + /** + * Resident set size in bytes (total physical memory used) (filter: eq) + */ + vm_rss_bytes_eq?: number; + /** + * Resident set size in bytes (total physical memory used) (filter: ne) + */ + vm_rss_bytes_ne?: number; + /** + * Resident set size in bytes (total physical memory used) (filter: lt) + */ + vm_rss_bytes_lt?: number; + /** + * Resident set size in bytes (total physical memory used) (filter: lte) + */ + vm_rss_bytes_lte?: number; + /** + * Resident set size in bytes (total physical memory used) (filter: gt) + */ + vm_rss_bytes_gt?: number; + /** + * Resident set size in bytes (total physical memory used) (filter: gte) + */ + vm_rss_bytes_gte?: number; + /** + * Resident set size in bytes (total physical memory used) (filter: between_min) + */ + vm_rss_bytes_between_min?: number; + /** + * Resident set size in bytes (total physical memory used) (filter: between_max_value) + */ + vm_rss_bytes_between_max_value?: number; + /** + * Resident set size in bytes (total physical memory used) (filter: in_values) (comma-separated list) + */ + vm_rss_bytes_in_values?: string; + /** + * Resident set size in bytes (total physical memory used) (filter: not_in_values) (comma-separated list) + */ + vm_rss_bytes_not_in_values?: string; + /** + * Anonymous RSS in bytes (heap, stack, anonymous mmap) (filter: eq) + */ + rss_anon_bytes_eq?: number; + /** + * Anonymous RSS in bytes (heap, stack, anonymous mmap) (filter: ne) + */ + rss_anon_bytes_ne?: number; + /** + * Anonymous RSS in bytes (heap, stack, anonymous mmap) (filter: lt) + */ + rss_anon_bytes_lt?: number; + /** + * Anonymous RSS in bytes (heap, stack, anonymous mmap) (filter: lte) + */ + rss_anon_bytes_lte?: number; + /** + * Anonymous RSS in bytes (heap, stack, anonymous mmap) (filter: gt) + */ + rss_anon_bytes_gt?: number; + /** + * Anonymous RSS in bytes (heap, stack, anonymous mmap) (filter: gte) + */ + rss_anon_bytes_gte?: number; + /** + * Anonymous RSS in bytes (heap, stack, anonymous mmap) (filter: between_min) + */ + rss_anon_bytes_between_min?: number; + /** + * Anonymous RSS in bytes (heap, stack, anonymous mmap) (filter: between_max_value) + */ + rss_anon_bytes_between_max_value?: number; + /** + * Anonymous RSS in bytes (heap, stack, anonymous mmap) (filter: in_values) (comma-separated list) + */ + rss_anon_bytes_in_values?: string; + /** + * Anonymous RSS in bytes (heap, stack, anonymous mmap) (filter: not_in_values) (comma-separated list) + */ + rss_anon_bytes_not_in_values?: string; + /** + * File-backed RSS in bytes (shared libraries, mmap files) (filter: eq) + */ + rss_file_bytes_eq?: number; + /** + * File-backed RSS in bytes (shared libraries, mmap files) (filter: ne) + */ + rss_file_bytes_ne?: number; + /** + * File-backed RSS in bytes (shared libraries, mmap files) (filter: lt) + */ + rss_file_bytes_lt?: number; + /** + * File-backed RSS in bytes (shared libraries, mmap files) (filter: lte) + */ + rss_file_bytes_lte?: number; + /** + * File-backed RSS in bytes (shared libraries, mmap files) (filter: gt) + */ + rss_file_bytes_gt?: number; + /** + * File-backed RSS in bytes (shared libraries, mmap files) (filter: gte) + */ + rss_file_bytes_gte?: number; + /** + * File-backed RSS in bytes (shared libraries, mmap files) (filter: between_min) + */ + rss_file_bytes_between_min?: number; + /** + * File-backed RSS in bytes (shared libraries, mmap files) (filter: between_max_value) + */ + rss_file_bytes_between_max_value?: number; + /** + * File-backed RSS in bytes (shared libraries, mmap files) (filter: in_values) (comma-separated list) + */ + rss_file_bytes_in_values?: string; + /** + * File-backed RSS in bytes (shared libraries, mmap files) (filter: not_in_values) (comma-separated list) + */ + rss_file_bytes_not_in_values?: string; + /** + * Swap usage in bytes (filter: eq) + */ + vm_swap_bytes_eq?: number; + /** + * Swap usage in bytes (filter: ne) + */ + vm_swap_bytes_ne?: number; + /** + * Swap usage in bytes (filter: lt) + */ + vm_swap_bytes_lt?: number; + /** + * Swap usage in bytes (filter: lte) + */ + vm_swap_bytes_lte?: number; + /** + * Swap usage in bytes (filter: gt) + */ + vm_swap_bytes_gt?: number; + /** + * Swap usage in bytes (filter: gte) + */ + vm_swap_bytes_gte?: number; + /** + * Swap usage in bytes (filter: between_min) + */ + vm_swap_bytes_between_min?: number; + /** + * Swap usage in bytes (filter: between_max_value) + */ + vm_swap_bytes_between_max_value?: number; + /** + * Swap usage in bytes (filter: in_values) (comma-separated list) + */ + vm_swap_bytes_in_values?: string; + /** + * Swap usage in bytes (filter: not_in_values) (comma-separated list) + */ + vm_swap_bytes_not_in_values?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: eq) + */ + node_class_eq?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: ne) + */ + node_class_ne?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: contains) + */ + node_class_contains?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: starts_with) + */ + node_class_starts_with?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: ends_with) + */ + node_class_ends_with?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: like) + */ + node_class_like?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: not_like) + */ + node_class_not_like?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: in_values) (comma-separated list) + */ + node_class_in_values?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: not_in_values) (comma-separated list) + */ + node_class_not_in_values?: string; + /** + * The maximum number of fct_node_memory_usage_by_process to return. If unspecified, at most 100 items will be returned. The maximum value is 10000; values above 10000 will be coerced to 10000. + */ + page_size?: number; + /** + * A page token, received from a previous `ListFctNodeMemoryUsageByProcess` call. Provide this to retrieve the subsequent page. + */ + page_token?: string; + /** + * The order of results. Format: comma-separated list of fields. Example: "foo,bar" or "foo desc,bar" for descending order on foo. If unspecified, results will be returned in the default order. + */ + order_by?: string; + }; + url: '/api/v1/fct_node_memory_usage_by_process'; +}; + +export type FctNodeMemoryUsageByProcessServiceListErrors = { + /** + * Default error response + */ + default: Status; +}; + +export type FctNodeMemoryUsageByProcessServiceListError = + FctNodeMemoryUsageByProcessServiceListErrors[keyof FctNodeMemoryUsageByProcessServiceListErrors]; + +export type FctNodeMemoryUsageByProcessServiceListResponses = { + /** + * OK + */ + 200: ListFctNodeMemoryUsageByProcessResponse; +}; + +export type FctNodeMemoryUsageByProcessServiceListResponse = + FctNodeMemoryUsageByProcessServiceListResponses[keyof FctNodeMemoryUsageByProcessServiceListResponses]; + +export type FctNodeMemoryUsageByProcessServiceGetData = { + body?: never; + path: { + /** + * The wall clock time when the slot started + */ + wallclock_slot_start_date_time: number; + }; + query?: never; + url: '/api/v1/fct_node_memory_usage_by_process/{wallclock_slot_start_date_time}'; +}; + +export type FctNodeMemoryUsageByProcessServiceGetErrors = { + /** + * Default error response + */ + default: Status; +}; + +export type FctNodeMemoryUsageByProcessServiceGetError = + FctNodeMemoryUsageByProcessServiceGetErrors[keyof FctNodeMemoryUsageByProcessServiceGetErrors]; + +export type FctNodeMemoryUsageByProcessServiceGetResponses = { + /** + * OK + */ + 200: GetFctNodeMemoryUsageByProcessResponse; +}; + +export type FctNodeMemoryUsageByProcessServiceGetResponse = + FctNodeMemoryUsageByProcessServiceGetResponses[keyof FctNodeMemoryUsageByProcessServiceGetResponses]; + +export type FctNodeNetworkIoByProcessServiceListData = { + body?: never; + path?: never; + query?: { + /** + * The wall clock time when the slot started (filter: eq) + */ + wallclock_slot_start_date_time_eq?: number; + /** + * The wall clock time when the slot started (filter: ne) + */ + wallclock_slot_start_date_time_ne?: number; + /** + * The wall clock time when the slot started (filter: lt) + */ + wallclock_slot_start_date_time_lt?: number; + /** + * The wall clock time when the slot started (filter: lte) + */ + wallclock_slot_start_date_time_lte?: number; + /** + * The wall clock time when the slot started (filter: gt) + */ + wallclock_slot_start_date_time_gt?: number; + /** + * The wall clock time when the slot started (filter: gte) + */ + wallclock_slot_start_date_time_gte?: number; + /** + * The wall clock time when the slot started (filter: between_min) + */ + wallclock_slot_start_date_time_between_min?: number; + /** + * The wall clock time when the slot started (filter: between_max_value) + */ + wallclock_slot_start_date_time_between_max_value?: number; + /** + * The wall clock time when the slot started (filter: in_values) (comma-separated list) + */ + wallclock_slot_start_date_time_in_values?: string; + /** + * The wall clock time when the slot started (filter: not_in_values) (comma-separated list) + */ + wallclock_slot_start_date_time_not_in_values?: string; + /** + * Name of the observoor client that collected the data (filter: eq) + */ + meta_client_name_eq?: string; + /** + * Name of the observoor client that collected the data (filter: ne) + */ + meta_client_name_ne?: string; + /** + * Name of the observoor client that collected the data (filter: contains) + */ + meta_client_name_contains?: string; + /** + * Name of the observoor client that collected the data (filter: starts_with) + */ + meta_client_name_starts_with?: string; + /** + * Name of the observoor client that collected the data (filter: ends_with) + */ + meta_client_name_ends_with?: string; + /** + * Name of the observoor client that collected the data (filter: like) + */ + meta_client_name_like?: string; + /** + * Name of the observoor client that collected the data (filter: not_like) + */ + meta_client_name_not_like?: string; + /** + * Name of the observoor client that collected the data (filter: in_values) (comma-separated list) + */ + meta_client_name_in_values?: string; + /** + * Name of the observoor client that collected the data (filter: not_in_values) (comma-separated list) + */ + meta_client_name_not_in_values?: string; + /** + * Client type: CL or EL (filter: eq) + */ + client_type_eq?: string; + /** + * Client type: CL or EL (filter: ne) + */ + client_type_ne?: string; + /** + * Client type: CL or EL (filter: contains) + */ + client_type_contains?: string; + /** + * Client type: CL or EL (filter: starts_with) + */ + client_type_starts_with?: string; + /** + * Client type: CL or EL (filter: ends_with) + */ + client_type_ends_with?: string; + /** + * Client type: CL or EL (filter: like) + */ + client_type_like?: string; + /** + * Client type: CL or EL (filter: not_like) + */ + client_type_not_like?: string; + /** + * Client type: CL or EL (filter: in_values) (comma-separated list) + */ + client_type_in_values?: string; + /** + * Client type: CL or EL (filter: not_in_values) (comma-separated list) + */ + client_type_not_in_values?: string; + /** + * Process ID of the monitored client (filter: eq) + */ + pid_eq?: number; + /** + * Process ID of the monitored client (filter: ne) + */ + pid_ne?: number; + /** + * Process ID of the monitored client (filter: lt) + */ + pid_lt?: number; + /** + * Process ID of the monitored client (filter: lte) + */ + pid_lte?: number; + /** + * Process ID of the monitored client (filter: gt) + */ + pid_gt?: number; + /** + * Process ID of the monitored client (filter: gte) + */ + pid_gte?: number; + /** + * Process ID of the monitored client (filter: between_min) + */ + pid_between_min?: number; + /** + * Process ID of the monitored client (filter: between_max_value) + */ + pid_between_max_value?: number; + /** + * Process ID of the monitored client (filter: in_values) (comma-separated list) + */ + pid_in_values?: string; + /** + * Process ID of the monitored client (filter: not_in_values) (comma-separated list) + */ + pid_not_in_values?: string; + /** + * Port classification (e.g. cl_p2p_tcp, el_json_rpc, unknown) (filter: eq) + */ + port_label_eq?: string; + /** + * Port classification (e.g. cl_p2p_tcp, el_json_rpc, unknown) (filter: ne) + */ + port_label_ne?: string; + /** + * Port classification (e.g. cl_p2p_tcp, el_json_rpc, unknown) (filter: contains) + */ + port_label_contains?: string; + /** + * Port classification (e.g. cl_p2p_tcp, el_json_rpc, unknown) (filter: starts_with) + */ + port_label_starts_with?: string; + /** + * Port classification (e.g. cl_p2p_tcp, el_json_rpc, unknown) (filter: ends_with) + */ + port_label_ends_with?: string; + /** + * Port classification (e.g. cl_p2p_tcp, el_json_rpc, unknown) (filter: like) + */ + port_label_like?: string; + /** + * Port classification (e.g. cl_p2p_tcp, el_json_rpc, unknown) (filter: not_like) + */ + port_label_not_like?: string; + /** + * Port classification (e.g. cl_p2p_tcp, el_json_rpc, unknown) (filter: in_values) (comma-separated list) + */ + port_label_in_values?: string; + /** + * Port classification (e.g. cl_p2p_tcp, el_json_rpc, unknown) (filter: not_in_values) (comma-separated list) + */ + port_label_not_in_values?: string; + /** + * Traffic direction: tx or rx (filter: eq) + */ + direction_eq?: string; + /** + * Traffic direction: tx or rx (filter: ne) + */ + direction_ne?: string; + /** + * Traffic direction: tx or rx (filter: contains) + */ + direction_contains?: string; + /** + * Traffic direction: tx or rx (filter: starts_with) + */ + direction_starts_with?: string; + /** + * Traffic direction: tx or rx (filter: ends_with) + */ + direction_ends_with?: string; + /** + * Traffic direction: tx or rx (filter: like) + */ + direction_like?: string; + /** + * Traffic direction: tx or rx (filter: not_like) + */ + direction_not_like?: string; + /** + * Traffic direction: tx or rx (filter: in_values) (comma-separated list) + */ + direction_in_values?: string; + /** + * Traffic direction: tx or rx (filter: not_in_values) (comma-separated list) + */ + direction_not_in_values?: string; + /** + * Start of the sub-slot aggregation window (filter: eq) + */ + window_start_eq?: number; + /** + * Start of the sub-slot aggregation window (filter: ne) + */ + window_start_ne?: number; + /** + * Start of the sub-slot aggregation window (filter: lt) + */ + window_start_lt?: number; + /** + * Start of the sub-slot aggregation window (filter: lte) + */ + window_start_lte?: number; + /** + * Start of the sub-slot aggregation window (filter: gt) + */ + window_start_gt?: number; + /** + * Start of the sub-slot aggregation window (filter: gte) + */ + window_start_gte?: number; + /** + * Start of the sub-slot aggregation window (filter: between_min) + */ + window_start_between_min?: number; + /** + * Start of the sub-slot aggregation window (filter: between_max_value) + */ + window_start_between_max_value?: number; + /** + * Start of the sub-slot aggregation window (filter: in_values) (comma-separated list) + */ + window_start_in_values?: string; + /** + * Start of the sub-slot aggregation window (filter: not_in_values) (comma-separated list) + */ + window_start_not_in_values?: string; + /** + * Timestamp when the record was last updated (filter: eq) + */ + updated_date_time_eq?: number; + /** + * Timestamp when the record was last updated (filter: ne) + */ + updated_date_time_ne?: number; + /** + * Timestamp when the record was last updated (filter: lt) + */ + updated_date_time_lt?: number; + /** + * Timestamp when the record was last updated (filter: lte) + */ + updated_date_time_lte?: number; + /** + * Timestamp when the record was last updated (filter: gt) + */ + updated_date_time_gt?: number; + /** + * Timestamp when the record was last updated (filter: gte) + */ + updated_date_time_gte?: number; + /** + * Timestamp when the record was last updated (filter: between_min) + */ + updated_date_time_between_min?: number; + /** + * Timestamp when the record was last updated (filter: between_max_value) + */ + updated_date_time_between_max_value?: number; + /** + * Timestamp when the record was last updated (filter: in_values) (comma-separated list) + */ + updated_date_time_in_values?: string; + /** + * Timestamp when the record was last updated (filter: not_in_values) (comma-separated list) + */ + updated_date_time_not_in_values?: string; + /** + * The wallclock slot number (filter: eq) + */ + wallclock_slot_eq?: number; + /** + * The wallclock slot number (filter: ne) + */ + wallclock_slot_ne?: number; + /** + * The wallclock slot number (filter: lt) + */ + wallclock_slot_lt?: number; + /** + * The wallclock slot number (filter: lte) + */ + wallclock_slot_lte?: number; + /** + * The wallclock slot number (filter: gt) + */ + wallclock_slot_gt?: number; + /** + * The wallclock slot number (filter: gte) + */ + wallclock_slot_gte?: number; + /** + * The wallclock slot number (filter: between_min) + */ + wallclock_slot_between_min?: number; + /** + * The wallclock slot number (filter: between_max_value) + */ + wallclock_slot_between_max_value?: number; + /** + * The wallclock slot number (filter: in_values) (comma-separated list) + */ + wallclock_slot_in_values?: string; + /** + * The wallclock slot number (filter: not_in_values) (comma-separated list) + */ + wallclock_slot_not_in_values?: string; + /** + * Ethereum network name (filter: eq) + */ + meta_network_name_eq?: string; + /** + * Ethereum network name (filter: ne) + */ + meta_network_name_ne?: string; + /** + * Ethereum network name (filter: contains) + */ + meta_network_name_contains?: string; + /** + * Ethereum network name (filter: starts_with) + */ + meta_network_name_starts_with?: string; + /** + * Ethereum network name (filter: ends_with) + */ + meta_network_name_ends_with?: string; + /** + * Ethereum network name (filter: like) + */ + meta_network_name_like?: string; + /** + * Ethereum network name (filter: not_like) + */ + meta_network_name_not_like?: string; + /** + * Ethereum network name (filter: in_values) (comma-separated list) + */ + meta_network_name_in_values?: string; + /** + * Ethereum network name (filter: not_in_values) (comma-separated list) + */ + meta_network_name_not_in_values?: string; + /** + * Filter io_bytes using value + */ + io_bytes_value?: number; + /** + * Total packet or event count in this window (filter: eq) + */ + io_count_eq?: number; + /** + * Total packet or event count in this window (filter: ne) + */ + io_count_ne?: number; + /** + * Total packet or event count in this window (filter: lt) + */ + io_count_lt?: number; + /** + * Total packet or event count in this window (filter: lte) + */ + io_count_lte?: number; + /** + * Total packet or event count in this window (filter: gt) + */ + io_count_gt?: number; + /** + * Total packet or event count in this window (filter: gte) + */ + io_count_gte?: number; + /** + * Total packet or event count in this window (filter: between_min) + */ + io_count_between_min?: number; + /** + * Total packet or event count in this window (filter: between_max_value) + */ + io_count_between_max_value?: number; + /** + * Total packet or event count in this window (filter: in_values) (comma-separated list) + */ + io_count_in_values?: string; + /** + * Total packet or event count in this window (filter: not_in_values) (comma-separated list) + */ + io_count_not_in_values?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: eq) + */ + node_class_eq?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: ne) + */ + node_class_ne?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: contains) + */ + node_class_contains?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: starts_with) + */ + node_class_starts_with?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: ends_with) + */ + node_class_ends_with?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: like) + */ + node_class_like?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: not_like) + */ + node_class_not_like?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: in_values) (comma-separated list) + */ + node_class_in_values?: string; + /** + * Node classification for filtering (e.g. eip7870) (filter: not_in_values) (comma-separated list) + */ + node_class_not_in_values?: string; + /** + * The maximum number of fct_node_network_io_by_process to return. If unspecified, at most 100 items will be returned. The maximum value is 10000; values above 10000 will be coerced to 10000. + */ + page_size?: number; + /** + * A page token, received from a previous `ListFctNodeNetworkIoByProcess` call. Provide this to retrieve the subsequent page. + */ + page_token?: string; + /** + * The order of results. Format: comma-separated list of fields. Example: "foo,bar" or "foo desc,bar" for descending order on foo. If unspecified, results will be returned in the default order. + */ + order_by?: string; + }; + url: '/api/v1/fct_node_network_io_by_process'; +}; + +export type FctNodeNetworkIoByProcessServiceListErrors = { + /** + * Default error response + */ + default: Status; +}; + +export type FctNodeNetworkIoByProcessServiceListError = + FctNodeNetworkIoByProcessServiceListErrors[keyof FctNodeNetworkIoByProcessServiceListErrors]; + +export type FctNodeNetworkIoByProcessServiceListResponses = { + /** + * OK + */ + 200: ListFctNodeNetworkIoByProcessResponse; +}; + +export type FctNodeNetworkIoByProcessServiceListResponse = + FctNodeNetworkIoByProcessServiceListResponses[keyof FctNodeNetworkIoByProcessServiceListResponses]; + +export type FctNodeNetworkIoByProcessServiceGetData = { + body?: never; + path: { + /** + * The wall clock time when the slot started + */ + wallclock_slot_start_date_time: number; + }; + query?: never; + url: '/api/v1/fct_node_network_io_by_process/{wallclock_slot_start_date_time}'; +}; + +export type FctNodeNetworkIoByProcessServiceGetErrors = { + /** + * Default error response + */ + default: Status; +}; + +export type FctNodeNetworkIoByProcessServiceGetError = + FctNodeNetworkIoByProcessServiceGetErrors[keyof FctNodeNetworkIoByProcessServiceGetErrors]; + +export type FctNodeNetworkIoByProcessServiceGetResponses = { + /** + * OK + */ + 200: GetFctNodeNetworkIoByProcessResponse; +}; + +export type FctNodeNetworkIoByProcessServiceGetResponse = + FctNodeNetworkIoByProcessServiceGetResponses[keyof FctNodeNetworkIoByProcessServiceGetResponses]; + export type FctOpcodeGasByOpcodeDailyServiceListData = { body?: never; path?: never; diff --git a/src/api/zod.gen.ts b/src/api/zod.gen.ts index 967e48d38..99d0f0579 100644 --- a/src/api/zod.gen.ts +++ b/src/api/zod.gen.ts @@ -6697,6 +6697,232 @@ export const zFctNodeCpuUtilizationByProcess = z.object({ ), }); +export const zFctNodeDiskIoByProcess = z.object({ + client_type: z.optional(z.string()), + io_bytes: z.optional(z.number()), + io_ops: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + meta_client_name: z.optional(z.string()), + meta_network_name: z.optional(z.string()), + node_class: z.optional(z.string()), + pid: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + rw: z.optional(z.string()), + updated_date_time: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_start_date_time: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), +}); + +export const zFctNodeMemoryUsageByProcess = z.object({ + client_type: z.optional(z.string()), + meta_client_name: z.optional(z.string()), + meta_network_name: z.optional(z.string()), + node_class: z.optional(z.string()), + pid: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + rss_anon_bytes: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + rss_file_bytes: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + updated_date_time: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + vm_rss_bytes: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + vm_swap_bytes: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + wallclock_slot: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_start_date_time: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), +}); + +export const zFctNodeNetworkIoByProcess = z.object({ + client_type: z.optional(z.string()), + direction: z.optional(z.string()), + io_bytes: z.optional(z.number()), + io_count: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + meta_client_name: z.optional(z.string()), + meta_network_name: z.optional(z.string()), + node_class: z.optional(z.string()), + pid: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + port_label: z.optional(z.string()), + updated_date_time: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_start_date_time: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), +}); + export const zFctOpcodeGasByOpcodeDaily = z.object({ avg_count_per_block: z.optional(z.number()), avg_gas_per_block: z.optional(z.number()), @@ -8655,6 +8881,27 @@ export const zGetFctNodeCpuUtilizationByProcessResponse = z.object({ item: z.optional(zFctNodeCpuUtilizationByProcess), }); +/** + * Response for getting a single fct_node_disk_io_by_process record + */ +export const zGetFctNodeDiskIoByProcessResponse = z.object({ + item: z.optional(zFctNodeDiskIoByProcess), +}); + +/** + * Response for getting a single fct_node_memory_usage_by_process record + */ +export const zGetFctNodeMemoryUsageByProcessResponse = z.object({ + item: z.optional(zFctNodeMemoryUsageByProcess), +}); + +/** + * Response for getting a single fct_node_network_io_by_process record + */ +export const zGetFctNodeNetworkIoByProcessResponse = z.object({ + item: z.optional(zFctNodeNetworkIoByProcess), +}); + /** * Response for getting a single fct_opcode_gas_by_opcode_daily record */ @@ -13813,6 +14060,30 @@ export const zListFctNodeCpuUtilizationByProcessResponse = z.object({ next_page_token: z.optional(z.string()), }); +/** + * Response for listing fct_node_disk_io_by_process records + */ +export const zListFctNodeDiskIoByProcessResponse = z.object({ + fct_node_disk_io_by_process: z.optional(z.array(zFctNodeDiskIoByProcess)), + next_page_token: z.optional(z.string()), +}); + +/** + * Response for listing fct_node_memory_usage_by_process records + */ +export const zListFctNodeMemoryUsageByProcessResponse = z.object({ + fct_node_memory_usage_by_process: z.optional(z.array(zFctNodeMemoryUsageByProcess)), + next_page_token: z.optional(z.string()), +}); + +/** + * Response for listing fct_node_network_io_by_process records + */ +export const zListFctNodeNetworkIoByProcessResponse = z.object({ + fct_node_network_io_by_process: z.optional(z.array(zFctNodeNetworkIoByProcess)), + next_page_token: z.optional(z.string()), +}); + /** * Response for listing fct_opcode_gas_by_opcode_daily records */ @@ -69511,6 +69782,1923 @@ export const zFctNodeCpuUtilizationByProcessServiceGetData = z.object({ */ export const zFctNodeCpuUtilizationByProcessServiceGetResponse = zGetFctNodeCpuUtilizationByProcessResponse; +export const zFctNodeDiskIoByProcessServiceListData = z.object({ + body: z.optional(z.never()), + path: z.optional(z.never()), + query: z.optional( + z.object({ + wallclock_slot_start_date_time_eq: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_ne: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_lt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_lte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_gt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_gte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_between_min: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_between_max_value: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_in_values: z.optional(z.string().check(z.regex(/^-?\d+(,-?\d+)*$/))), + wallclock_slot_start_date_time_not_in_values: z.optional(z.string().check(z.regex(/^-?\d+(,-?\d+)*$/))), + meta_client_name_eq: z.optional(z.string()), + meta_client_name_ne: z.optional(z.string()), + meta_client_name_contains: z.optional(z.string()), + meta_client_name_starts_with: z.optional(z.string()), + meta_client_name_ends_with: z.optional(z.string()), + meta_client_name_like: z.optional(z.string()), + meta_client_name_not_like: z.optional(z.string()), + meta_client_name_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + meta_client_name_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + client_type_eq: z.optional(z.string()), + client_type_ne: z.optional(z.string()), + client_type_contains: z.optional(z.string()), + client_type_starts_with: z.optional(z.string()), + client_type_ends_with: z.optional(z.string()), + client_type_like: z.optional(z.string()), + client_type_not_like: z.optional(z.string()), + client_type_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + client_type_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + pid_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + pid_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + rw_eq: z.optional(z.string()), + rw_ne: z.optional(z.string()), + rw_contains: z.optional(z.string()), + rw_starts_with: z.optional(z.string()), + rw_ends_with: z.optional(z.string()), + rw_like: z.optional(z.string()), + rw_not_like: z.optional(z.string()), + rw_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + rw_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + window_start_eq: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_ne: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_lt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_lte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_gt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_gte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_between_min: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_between_max_value: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_in_values: z.optional(z.string().check(z.regex(/^-?\d+(,-?\d+)*$/))), + window_start_not_in_values: z.optional(z.string().check(z.regex(/^-?\d+(,-?\d+)*$/))), + updated_date_time_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + updated_date_time_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + wallclock_slot_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + wallclock_slot_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + meta_network_name_eq: z.optional(z.string()), + meta_network_name_ne: z.optional(z.string()), + meta_network_name_contains: z.optional(z.string()), + meta_network_name_starts_with: z.optional(z.string()), + meta_network_name_ends_with: z.optional(z.string()), + meta_network_name_like: z.optional(z.string()), + meta_network_name_not_like: z.optional(z.string()), + meta_network_name_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + meta_network_name_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + io_bytes_value: z.optional(z.number()), + io_ops_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + io_ops_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + io_ops_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + io_ops_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + io_ops_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + io_ops_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + io_ops_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + io_ops_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + io_ops_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + io_ops_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + node_class_eq: z.optional(z.string()), + node_class_ne: z.optional(z.string()), + node_class_contains: z.optional(z.string()), + node_class_starts_with: z.optional(z.string()), + node_class_ends_with: z.optional(z.string()), + node_class_like: z.optional(z.string()), + node_class_not_like: z.optional(z.string()), + node_class_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + node_class_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + page_size: z.optional( + z + .int() + .check( + z.minimum(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }), + z.maximum(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }) + ) + ), + page_token: z.optional(z.string()), + order_by: z.optional(z.string()), + }) + ), +}); + +/** + * OK + */ +export const zFctNodeDiskIoByProcessServiceListResponse = zListFctNodeDiskIoByProcessResponse; + +export const zFctNodeDiskIoByProcessServiceGetData = z.object({ + body: z.optional(z.never()), + path: z.object({ + wallclock_slot_start_date_time: z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ), + }), + query: z.optional(z.never()), +}); + +/** + * OK + */ +export const zFctNodeDiskIoByProcessServiceGetResponse = zGetFctNodeDiskIoByProcessResponse; + +export const zFctNodeMemoryUsageByProcessServiceListData = z.object({ + body: z.optional(z.never()), + path: z.optional(z.never()), + query: z.optional( + z.object({ + wallclock_slot_start_date_time_eq: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_ne: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_lt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_lte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_gt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_gte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_between_min: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_between_max_value: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_in_values: z.optional(z.string().check(z.regex(/^-?\d+(,-?\d+)*$/))), + wallclock_slot_start_date_time_not_in_values: z.optional(z.string().check(z.regex(/^-?\d+(,-?\d+)*$/))), + meta_client_name_eq: z.optional(z.string()), + meta_client_name_ne: z.optional(z.string()), + meta_client_name_contains: z.optional(z.string()), + meta_client_name_starts_with: z.optional(z.string()), + meta_client_name_ends_with: z.optional(z.string()), + meta_client_name_like: z.optional(z.string()), + meta_client_name_not_like: z.optional(z.string()), + meta_client_name_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + meta_client_name_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + client_type_eq: z.optional(z.string()), + client_type_ne: z.optional(z.string()), + client_type_contains: z.optional(z.string()), + client_type_starts_with: z.optional(z.string()), + client_type_ends_with: z.optional(z.string()), + client_type_like: z.optional(z.string()), + client_type_not_like: z.optional(z.string()), + client_type_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + client_type_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + pid_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + pid_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + window_start_eq: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_ne: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_lt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_lte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_gt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_gte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_between_min: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_between_max_value: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_in_values: z.optional(z.string().check(z.regex(/^-?\d+(,-?\d+)*$/))), + window_start_not_in_values: z.optional(z.string().check(z.regex(/^-?\d+(,-?\d+)*$/))), + updated_date_time_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + updated_date_time_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + wallclock_slot_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + wallclock_slot_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + meta_network_name_eq: z.optional(z.string()), + meta_network_name_ne: z.optional(z.string()), + meta_network_name_contains: z.optional(z.string()), + meta_network_name_starts_with: z.optional(z.string()), + meta_network_name_ends_with: z.optional(z.string()), + meta_network_name_like: z.optional(z.string()), + meta_network_name_not_like: z.optional(z.string()), + meta_network_name_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + meta_network_name_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + vm_rss_bytes_eq: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + vm_rss_bytes_ne: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + vm_rss_bytes_lt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + vm_rss_bytes_lte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + vm_rss_bytes_gt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + vm_rss_bytes_gte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + vm_rss_bytes_between_min: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + vm_rss_bytes_between_max_value: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + vm_rss_bytes_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + vm_rss_bytes_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + rss_anon_bytes_eq: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + rss_anon_bytes_ne: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + rss_anon_bytes_lt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + rss_anon_bytes_lte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + rss_anon_bytes_gt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + rss_anon_bytes_gte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + rss_anon_bytes_between_min: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + rss_anon_bytes_between_max_value: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + rss_anon_bytes_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + rss_anon_bytes_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + rss_file_bytes_eq: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + rss_file_bytes_ne: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + rss_file_bytes_lt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + rss_file_bytes_lte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + rss_file_bytes_gt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + rss_file_bytes_gte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + rss_file_bytes_between_min: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + rss_file_bytes_between_max_value: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + rss_file_bytes_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + rss_file_bytes_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + vm_swap_bytes_eq: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + vm_swap_bytes_ne: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + vm_swap_bytes_lt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + vm_swap_bytes_lte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + vm_swap_bytes_gt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + vm_swap_bytes_gte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + vm_swap_bytes_between_min: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + vm_swap_bytes_between_max_value: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('0'), { error: 'Invalid value: Expected uint64 to be >= 0' }), + z.maximum(BigInt('18446744073709551615'), { + error: 'Invalid value: Expected uint64 to be <= 18446744073709551615', + }) + ) + ), + vm_swap_bytes_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + vm_swap_bytes_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + node_class_eq: z.optional(z.string()), + node_class_ne: z.optional(z.string()), + node_class_contains: z.optional(z.string()), + node_class_starts_with: z.optional(z.string()), + node_class_ends_with: z.optional(z.string()), + node_class_like: z.optional(z.string()), + node_class_not_like: z.optional(z.string()), + node_class_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + node_class_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + page_size: z.optional( + z + .int() + .check( + z.minimum(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }), + z.maximum(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }) + ) + ), + page_token: z.optional(z.string()), + order_by: z.optional(z.string()), + }) + ), +}); + +/** + * OK + */ +export const zFctNodeMemoryUsageByProcessServiceListResponse = zListFctNodeMemoryUsageByProcessResponse; + +export const zFctNodeMemoryUsageByProcessServiceGetData = z.object({ + body: z.optional(z.never()), + path: z.object({ + wallclock_slot_start_date_time: z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ), + }), + query: z.optional(z.never()), +}); + +/** + * OK + */ +export const zFctNodeMemoryUsageByProcessServiceGetResponse = zGetFctNodeMemoryUsageByProcessResponse; + +export const zFctNodeNetworkIoByProcessServiceListData = z.object({ + body: z.optional(z.never()), + path: z.optional(z.never()), + query: z.optional( + z.object({ + wallclock_slot_start_date_time_eq: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_ne: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_lt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_lte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_gt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_gte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_between_min: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_between_max_value: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + wallclock_slot_start_date_time_in_values: z.optional(z.string().check(z.regex(/^-?\d+(,-?\d+)*$/))), + wallclock_slot_start_date_time_not_in_values: z.optional(z.string().check(z.regex(/^-?\d+(,-?\d+)*$/))), + meta_client_name_eq: z.optional(z.string()), + meta_client_name_ne: z.optional(z.string()), + meta_client_name_contains: z.optional(z.string()), + meta_client_name_starts_with: z.optional(z.string()), + meta_client_name_ends_with: z.optional(z.string()), + meta_client_name_like: z.optional(z.string()), + meta_client_name_not_like: z.optional(z.string()), + meta_client_name_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + meta_client_name_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + client_type_eq: z.optional(z.string()), + client_type_ne: z.optional(z.string()), + client_type_contains: z.optional(z.string()), + client_type_starts_with: z.optional(z.string()), + client_type_ends_with: z.optional(z.string()), + client_type_like: z.optional(z.string()), + client_type_not_like: z.optional(z.string()), + client_type_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + client_type_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + pid_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + pid_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + pid_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + port_label_eq: z.optional(z.string()), + port_label_ne: z.optional(z.string()), + port_label_contains: z.optional(z.string()), + port_label_starts_with: z.optional(z.string()), + port_label_ends_with: z.optional(z.string()), + port_label_like: z.optional(z.string()), + port_label_not_like: z.optional(z.string()), + port_label_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + port_label_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + direction_eq: z.optional(z.string()), + direction_ne: z.optional(z.string()), + direction_contains: z.optional(z.string()), + direction_starts_with: z.optional(z.string()), + direction_ends_with: z.optional(z.string()), + direction_like: z.optional(z.string()), + direction_not_like: z.optional(z.string()), + direction_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + direction_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + window_start_eq: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_ne: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_lt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_lte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_gt: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_gte: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_between_min: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_between_max_value: z.optional( + z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ) + ), + window_start_in_values: z.optional(z.string().check(z.regex(/^-?\d+(,-?\d+)*$/))), + window_start_not_in_values: z.optional(z.string().check(z.regex(/^-?\d+(,-?\d+)*$/))), + updated_date_time_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + updated_date_time_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + updated_date_time_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + wallclock_slot_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + wallclock_slot_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + wallclock_slot_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + meta_network_name_eq: z.optional(z.string()), + meta_network_name_ne: z.optional(z.string()), + meta_network_name_contains: z.optional(z.string()), + meta_network_name_starts_with: z.optional(z.string()), + meta_network_name_ends_with: z.optional(z.string()), + meta_network_name_like: z.optional(z.string()), + meta_network_name_not_like: z.optional(z.string()), + meta_network_name_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + meta_network_name_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + io_bytes_value: z.optional(z.number()), + io_count_eq: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + io_count_ne: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + io_count_lt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + io_count_lte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + io_count_gt: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + io_count_gte: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + io_count_between_min: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + io_count_between_max_value: z.optional( + z + .int() + .check( + z.minimum(0, { error: 'Invalid value: Expected uint32 to be >= 0' }), + z.maximum(4294967295, { error: 'Invalid value: Expected uint32 to be <= 4294967295' }) + ) + ), + io_count_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + io_count_not_in_values: z.optional(z.string().check(z.regex(/^\d+(,\d+)*$/))), + node_class_eq: z.optional(z.string()), + node_class_ne: z.optional(z.string()), + node_class_contains: z.optional(z.string()), + node_class_starts_with: z.optional(z.string()), + node_class_ends_with: z.optional(z.string()), + node_class_like: z.optional(z.string()), + node_class_not_like: z.optional(z.string()), + node_class_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + node_class_not_in_values: z.optional(z.string().check(z.regex(/^[^,]+(,[^,]+)*$/))), + page_size: z.optional( + z + .int() + .check( + z.minimum(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }), + z.maximum(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }) + ) + ), + page_token: z.optional(z.string()), + order_by: z.optional(z.string()), + }) + ), +}); + +/** + * OK + */ +export const zFctNodeNetworkIoByProcessServiceListResponse = zListFctNodeNetworkIoByProcessResponse; + +export const zFctNodeNetworkIoByProcessServiceGetData = z.object({ + body: z.optional(z.never()), + path: z.object({ + wallclock_slot_start_date_time: z.coerce + .bigint() + .check( + z.minimum(BigInt('-9223372036854775808'), { + error: 'Invalid value: Expected int64 to be >= -9223372036854775808', + }), + z.maximum(BigInt('9223372036854775807'), { + error: 'Invalid value: Expected int64 to be <= 9223372036854775807', + }) + ), + }), + query: z.optional(z.never()), +}); + +/** + * OK + */ +export const zFctNodeNetworkIoByProcessServiceGetResponse = zGetFctNodeNetworkIoByProcessResponse; + export const zFctOpcodeGasByOpcodeDailyServiceListData = z.object({ body: z.optional(z.never()), path: z.optional(z.never()), diff --git a/src/pages/ethereum/slots/components/NodeResources/DiskIoChart.tsx b/src/pages/ethereum/slots/components/NodeResources/DiskIoChart.tsx new file mode 100644 index 000000000..c688d6a86 --- /dev/null +++ b/src/pages/ethereum/slots/components/NodeResources/DiskIoChart.tsx @@ -0,0 +1,341 @@ +import { type JSX, useMemo } from 'react'; +import { PopoutCard } from '@/components/Layout/PopoutCard'; +import { MultiLineChart } from '@/components/Charts/MultiLine'; +import type { SeriesData, MarkAreaConfig, MarkLineConfig } from '@/components/Charts/MultiLine/MultiLine.types'; +import { getDataVizColors, getClientLayer } from '@/utils'; +import { DEFAULT_BEACON_SLOT_PHASES } from '@/utils/beacon'; +import { ClientLogo } from '@/components/Ethereum/ClientLogo'; +import type { FctNodeDiskIoByProcess } from '@/api/types.gen'; +import { ANNOTATION_COLORS, type AnnotationType, type AnnotationEvent } from './types'; + +function usToSeconds(us: number): number { + return us / 1_000_000; +} + +function capitalize(s: string): string { + return s.charAt(0).toUpperCase() + s.slice(1); +} + +function bytesToKB(bytes: number): number { + return bytes / 1024; +} + +const MIN_AREA_WIDTH_SEC = 0.08; + +function nodeMatches(cpuNodeName: string, propNodeId: string): boolean { + const short = cpuNodeName.split('/').pop() ?? cpuNodeName; + return propNodeId === short || propNodeId === cpuNodeName || short.includes(propNodeId) || propNodeId.includes(short); +} + +function percentile(sorted: number[], p: number): number { + const idx = Math.floor(sorted.length * p); + return sorted[Math.min(idx, sorted.length - 1)]; +} + +const BUCKET_SIZE = 0.25; +const toBucket = (offsetSec: number): number => Math.round(offsetSec / BUCKET_SIZE) * BUCKET_SIZE; +const avg = (arr: number[]): number => arr.reduce((s, v) => s + v, 0) / arr.length; + +interface DiskIoChartProps { + data: FctNodeDiskIoByProcess[]; + selectedNode: string | null; + slot: number; + annotations: AnnotationEvent[]; + enabledAnnotations: Set; +} + +const PHASE_BOUNDARY_COLORS = ['#22d3ee', '#22c55e', '#f59e0b']; + +interface EChartsTooltipParam { + marker: string; + seriesName: string; + value: [number, number] | number; + axisValue?: number | string; +} + +export function DiskIoChart({ + data, + selectedNode, + slot, + annotations, + enabledAnnotations, +}: DiskIoChartProps): JSX.Element { + const { CHART_CATEGORICAL_COLORS } = getDataVizColors(); + + const { series, clClient, elClient } = useMemo(() => { + if (data.length === 0) { + return { series: [] as SeriesData[], clClient: '', elClient: '' }; + } + + const slotStartUs = Math.min(...data.map(d => d.wallclock_slot_start_date_time ?? 0).filter(v => v > 0)); + const chartSeries: SeriesData[] = []; + let resolvedClClient = ''; + let resolvedElClient = ''; + + const bucketData = (items: FctNodeDiskIoByProcess[]): Map => { + const buckets = new Map(); + for (const d of items) { + const offset = usToSeconds((d.window_start ?? 0) - slotStartUs); + const bucket = toBucket(offset); + if (bucket < 0 || bucket > 12) continue; + + if (!buckets.has(bucket)) buckets.set(bucket, []); + buckets.get(bucket)!.push(bytesToKB(d.io_bytes ?? 0)); + } + return buckets; + }; + + const toPoints = (buckets: Map): [number, number][] => + Array.from(buckets.entries()) + .sort(([a], [b]) => a - b) + .map(([t, vals]) => [t, avg(vals)] as [number, number]); + + if (selectedNode) { + const nodeData = data.filter(d => d.meta_client_name === selectedNode); + const clData = nodeData.filter(d => getClientLayer(d.client_type ?? '') === 'CL'); + const elData = nodeData.filter(d => getClientLayer(d.client_type ?? '') === 'EL'); + + resolvedClClient = clData[0]?.client_type ?? ''; + resolvedElClient = elData[0]?.client_type ?? ''; + + const clLabel = capitalize(resolvedClClient || 'CL'); + const elLabel = capitalize(resolvedElClient || 'EL'); + + const clRead = clData.filter(d => d.rw === 'read'); + const clWrite = clData.filter(d => d.rw === 'write'); + const elRead = elData.filter(d => d.rw === 'read'); + const elWrite = elData.filter(d => d.rw === 'write'); + + chartSeries.push({ + name: `${clLabel} Read`, + data: toPoints(bucketData(clRead)), + color: CHART_CATEGORICAL_COLORS[0], + lineWidth: 2, + showArea: true, + areaOpacity: 0.08, + }); + chartSeries.push({ + name: `${clLabel} Write`, + data: toPoints(bucketData(clWrite)), + color: CHART_CATEGORICAL_COLORS[0], + lineWidth: 1.5, + lineStyle: 'dashed', + showArea: false, + }); + chartSeries.push({ + name: `${elLabel} Read`, + data: toPoints(bucketData(elRead)), + color: CHART_CATEGORICAL_COLORS[1], + lineWidth: 2, + showArea: true, + areaOpacity: 0.08, + }); + chartSeries.push({ + name: `${elLabel} Write`, + data: toPoints(bucketData(elWrite)), + color: CHART_CATEGORICAL_COLORS[1], + lineWidth: 1.5, + lineStyle: 'dashed', + showArea: false, + }); + } else { + const readData = data.filter(d => d.rw === 'read'); + const writeData = data.filter(d => d.rw === 'write'); + + chartSeries.push({ + name: 'Read', + data: toPoints(bucketData(readData)), + color: CHART_CATEGORICAL_COLORS[0], + lineWidth: 2, + showArea: true, + areaOpacity: 0.08, + }); + chartSeries.push({ + name: 'Write', + data: toPoints(bucketData(writeData)), + color: CHART_CATEGORICAL_COLORS[1], + lineWidth: 2, + showArea: true, + areaOpacity: 0.08, + }); + } + + return { series: chartSeries, clClient: resolvedClClient, elClient: resolvedElClient }; + }, [data, selectedNode, CHART_CATEGORICAL_COLORS]); + + const markAreas = useMemo((): MarkAreaConfig[] => { + const areas: MarkAreaConfig[] = []; + + if (selectedNode) { + for (const anno of annotations) { + if (!enabledAnnotations.has(anno.type)) continue; + if (!anno.nodeName || !nodeMatches(selectedNode, anno.nodeName)) continue; + + const startSec = anno.timeMs / 1000; + if (startSec < 0 || startSec > 12) continue; + const color = ANNOTATION_COLORS[anno.type]; + const hasRange = anno.endMs != null && Math.abs(anno.endMs - anno.timeMs) > 10; + + if (hasRange) { + const endSec = Math.min(anno.endMs! / 1000, 12); + areas.push({ xStart: startSec, xEnd: endSec, color, opacity: 0.12 }); + } else { + areas.push({ + xStart: startSec - MIN_AREA_WIDTH_SEC / 2, + xEnd: startSec + MIN_AREA_WIDTH_SEC / 2, + color, + opacity: 0.3, + }); + } + } + } else { + const byType = new Map(); + for (const anno of annotations) { + if (!enabledAnnotations.has(anno.type)) continue; + if (!byType.has(anno.type)) byType.set(anno.type, []); + byType.get(anno.type)!.push(anno); + } + + for (const [type, events] of byType) { + const color = ANNOTATION_COLORS[type]; + const hasRanges = events.some(e => e.endMs != null); + + if (hasRanges) { + const starts = events.map(e => e.timeMs).sort((a, b) => a - b); + const ends = events.map(e => e.endMs ?? e.timeMs).sort((a, b) => a - b); + const startSec = starts[0] / 1000; + const endSec = percentile(ends, 0.95) / 1000; + if (startSec >= 0 && startSec <= 12) { + areas.push({ xStart: Math.max(0, startSec), xEnd: Math.min(12, endSec), color, opacity: 0.1 }); + } + } else { + const times = events.map(e => e.timeMs).sort((a, b) => a - b); + const minSec = times[0] / 1000; + const p95Sec = percentile(times, 0.95) / 1000; + if (minSec >= 0 && p95Sec <= 12) { + const width = p95Sec - minSec; + if (width < MIN_AREA_WIDTH_SEC) { + const medSec = percentile(times, 0.5) / 1000; + areas.push({ + xStart: medSec - MIN_AREA_WIDTH_SEC / 2, + xEnd: medSec + MIN_AREA_WIDTH_SEC / 2, + color, + opacity: 0.25, + }); + } else { + areas.push({ xStart: minSec, xEnd: p95Sec, color, opacity: 0.1 }); + } + } + } + } + } + + return areas; + }, [annotations, enabledAnnotations, selectedNode]); + + const markLines = useMemo((): MarkLineConfig[] => { + if (!enabledAnnotations.has('slot_phases')) return []; + + const lines: MarkLineConfig[] = []; + let cumulativeSec = 0; + + for (let i = 0; i < DEFAULT_BEACON_SLOT_PHASES.length - 1; i++) { + cumulativeSec += DEFAULT_BEACON_SLOT_PHASES[i].duration / 1000; + const nextPhase = DEFAULT_BEACON_SLOT_PHASES[i + 1]; + const color = PHASE_BOUNDARY_COLORS[i + 1] ?? '#6b7280'; + + lines.push({ + xValue: cumulativeSec, + label: nextPhase.label, + labelPosition: 'insideEndTop', + color, + lineStyle: 'dotted', + lineWidth: 1, + distance: [0, -8], + }); + } + + return lines; + }, [enabledAnnotations]); + + const nodeCount = new Set(data.map(d => d.meta_client_name)).size; + const shortNodeName = selectedNode?.split('/').pop() ?? ''; + + const subtitle = selectedNode + ? `Slot ${slot} · ${shortNodeName} · Disk I/O` + : `Slot ${slot} · Mean across ${nodeCount} nodes · Disk I/O`; + + const headerActions = + selectedNode && (clClient || elClient) ? ( +
+ {clClient && } + {elClient && } +
+ ) : undefined; + + if (data.length === 0) { + return ( + + {({ inModal }) => ( +
+
+

No disk I/O data available for this slot

+
+
+ )} +
+ ); + } + + return ( + + {({ inModal }) => ( + `${v}s`, + }} + yAxis={{ + name: 'KB', + min: 0, + formatter: (v: number) => `${v.toFixed(0)} KB`, + }} + height={inModal ? 500 : 350} + showLegend + legendPosition="bottom" + markLines={markLines} + markAreas={markAreas} + syncGroup="slot-time" + tooltipFormatter={(params: unknown) => { + const items = (Array.isArray(params) ? params : [params]) as EChartsTooltipParam[]; + if (items.length === 0) return ''; + + const first = items[0]; + const xVal = Array.isArray(first.value) ? first.value[0] : first.axisValue; + const timeStr = typeof xVal === 'number' ? `${xVal.toFixed(2)}s` : `${xVal}s`; + + let html = `
`; + html += `
${timeStr}
`; + + for (const p of items) { + const val = Array.isArray(p.value) ? p.value[1] : p.value; + if (val == null) continue; + html += `
`; + html += `${p.marker}`; + html += `${p.seriesName}`; + html += `${Number(val).toFixed(1)} KB`; + html += `
`; + } + + html += `
`; + return html; + }} + /> + )} +
+ ); +} diff --git a/src/pages/ethereum/slots/components/NodeResources/MemoryUsageChart.tsx b/src/pages/ethereum/slots/components/NodeResources/MemoryUsageChart.tsx new file mode 100644 index 000000000..450a1d64a --- /dev/null +++ b/src/pages/ethereum/slots/components/NodeResources/MemoryUsageChart.tsx @@ -0,0 +1,356 @@ +import { type JSX, useMemo } from 'react'; +import { PopoutCard } from '@/components/Layout/PopoutCard'; +import { MultiLineChart } from '@/components/Charts/MultiLine'; +import type { SeriesData, MarkAreaConfig, MarkLineConfig } from '@/components/Charts/MultiLine/MultiLine.types'; +import { getDataVizColors, getClientLayer } from '@/utils'; +import { DEFAULT_BEACON_SLOT_PHASES } from '@/utils/beacon'; +import { ClientLogo } from '@/components/Ethereum/ClientLogo'; +import { SelectMenu } from '@/components/Forms/SelectMenu'; +import type { FctNodeMemoryUsageByProcess } from '@/api/types.gen'; +import { ANNOTATION_COLORS, type AnnotationType, type AnnotationEvent } from './types'; + +function usToSeconds(us: number): number { + return us / 1_000_000; +} + +function capitalize(s: string): string { + return s.charAt(0).toUpperCase() + s.slice(1); +} + +function bytesToMB(bytes: number): number { + return bytes / (1024 * 1024); +} + +export type MemoryMetric = 'vm_rss' | 'rss_anon' | 'rss_file' | 'vm_swap'; + +const METRIC_LABELS: Record = { + vm_rss: 'RSS Total', + rss_anon: 'RSS Anon', + rss_file: 'RSS File', + vm_swap: 'Swap', +}; + +const METRIC_OPTIONS = [ + { value: 'vm_rss' as MemoryMetric, label: 'RSS Total' }, + { value: 'rss_anon' as MemoryMetric, label: 'RSS Anon' }, + { value: 'rss_file' as MemoryMetric, label: 'RSS File' }, + { value: 'vm_swap' as MemoryMetric, label: 'Swap' }, +]; + +const MIN_AREA_WIDTH_SEC = 0.08; + +function nodeMatches(cpuNodeName: string, propNodeId: string): boolean { + const short = cpuNodeName.split('/').pop() ?? cpuNodeName; + return propNodeId === short || propNodeId === cpuNodeName || short.includes(propNodeId) || propNodeId.includes(short); +} + +function percentile(sorted: number[], p: number): number { + const idx = Math.floor(sorted.length * p); + return sorted[Math.min(idx, sorted.length - 1)]; +} + +const BUCKET_SIZE = 0.25; +const toBucket = (offsetSec: number): number => Math.round(offsetSec / BUCKET_SIZE) * BUCKET_SIZE; +const avg = (arr: number[]): number => arr.reduce((s, v) => s + v, 0) / arr.length; + +function extractMetric(d: FctNodeMemoryUsageByProcess, metric: MemoryMetric): number { + switch (metric) { + case 'vm_rss': + return d.vm_rss_bytes ?? 0; + case 'rss_anon': + return d.rss_anon_bytes ?? 0; + case 'rss_file': + return d.rss_file_bytes ?? 0; + case 'vm_swap': + return d.vm_swap_bytes ?? 0; + } +} + +interface MemoryUsageChartProps { + data: FctNodeMemoryUsageByProcess[]; + selectedNode: string | null; + metric: MemoryMetric; + onMetricChange: (metric: MemoryMetric) => void; + slot: number; + annotations: AnnotationEvent[]; + enabledAnnotations: Set; +} + +const PHASE_BOUNDARY_COLORS = ['#22d3ee', '#22c55e', '#f59e0b']; + +interface EChartsTooltipParam { + marker: string; + seriesName: string; + value: [number, number] | number; + axisValue?: number | string; +} + +export function MemoryUsageChart({ + data, + selectedNode, + metric, + onMetricChange, + slot, + annotations, + enabledAnnotations, +}: MemoryUsageChartProps): JSX.Element { + const { CHART_CATEGORICAL_COLORS } = getDataVizColors(); + + const { series, clClient, elClient } = useMemo(() => { + if (data.length === 0) { + return { series: [] as SeriesData[], clClient: '', elClient: '' }; + } + + const slotStartUs = Math.min(...data.map(d => d.wallclock_slot_start_date_time ?? 0).filter(v => v > 0)); + const chartSeries: SeriesData[] = []; + let resolvedClClient = ''; + let resolvedElClient = ''; + + const bucketData = (items: FctNodeMemoryUsageByProcess[]): Map => { + const buckets = new Map(); + for (const d of items) { + const offset = usToSeconds((d.window_start ?? 0) - slotStartUs); + const bucket = toBucket(offset); + if (bucket < 0 || bucket > 12) continue; + + if (!buckets.has(bucket)) buckets.set(bucket, []); + buckets.get(bucket)!.push(bytesToMB(extractMetric(d, metric))); + } + return buckets; + }; + + const toPoints = (buckets: Map): [number, number][] => + Array.from(buckets.entries()) + .sort(([a], [b]) => a - b) + .map(([t, vals]) => [t, avg(vals)] as [number, number]); + + if (selectedNode) { + const nodeData = data.filter(d => d.meta_client_name === selectedNode); + const clData = nodeData.filter(d => getClientLayer(d.client_type ?? '') === 'CL'); + const elData = nodeData.filter(d => getClientLayer(d.client_type ?? '') === 'EL'); + + resolvedClClient = clData[0]?.client_type ?? ''; + resolvedElClient = elData[0]?.client_type ?? ''; + + chartSeries.push({ + name: capitalize(resolvedClClient || 'CL'), + data: toPoints(bucketData(clData)), + color: CHART_CATEGORICAL_COLORS[0], + lineWidth: 2, + showArea: true, + areaOpacity: 0.08, + }); + + chartSeries.push({ + name: capitalize(resolvedElClient || 'EL'), + data: toPoints(bucketData(elData)), + color: CHART_CATEGORICAL_COLORS[1], + lineWidth: 2, + showArea: true, + areaOpacity: 0.08, + }); + } else { + const clData = data.filter(d => getClientLayer(d.client_type ?? '') === 'CL'); + const elData = data.filter(d => getClientLayer(d.client_type ?? '') === 'EL'); + + chartSeries.push({ + name: 'Consensus Layer', + data: toPoints(bucketData(clData)), + color: CHART_CATEGORICAL_COLORS[0], + lineWidth: 2, + showArea: true, + areaOpacity: 0.08, + }); + + chartSeries.push({ + name: 'Execution Layer', + data: toPoints(bucketData(elData)), + color: CHART_CATEGORICAL_COLORS[1], + lineWidth: 2, + showArea: true, + areaOpacity: 0.08, + }); + } + + return { series: chartSeries, clClient: resolvedClClient, elClient: resolvedElClient }; + }, [data, selectedNode, metric, CHART_CATEGORICAL_COLORS]); + + const markAreas = useMemo((): MarkAreaConfig[] => { + const areas: MarkAreaConfig[] = []; + + if (selectedNode) { + for (const anno of annotations) { + if (!enabledAnnotations.has(anno.type)) continue; + if (!anno.nodeName || !nodeMatches(selectedNode, anno.nodeName)) continue; + + const startSec = anno.timeMs / 1000; + if (startSec < 0 || startSec > 12) continue; + const color = ANNOTATION_COLORS[anno.type]; + const hasRange = anno.endMs != null && Math.abs(anno.endMs - anno.timeMs) > 10; + + if (hasRange) { + const endSec = Math.min(anno.endMs! / 1000, 12); + areas.push({ xStart: startSec, xEnd: endSec, color, opacity: 0.12 }); + } else { + areas.push({ + xStart: startSec - MIN_AREA_WIDTH_SEC / 2, + xEnd: startSec + MIN_AREA_WIDTH_SEC / 2, + color, + opacity: 0.3, + }); + } + } + } else { + const byType = new Map(); + for (const anno of annotations) { + if (!enabledAnnotations.has(anno.type)) continue; + if (!byType.has(anno.type)) byType.set(anno.type, []); + byType.get(anno.type)!.push(anno); + } + + for (const [type, events] of byType) { + const color = ANNOTATION_COLORS[type]; + const hasRanges = events.some(e => e.endMs != null); + + if (hasRanges) { + const starts = events.map(e => e.timeMs).sort((a, b) => a - b); + const ends = events.map(e => e.endMs ?? e.timeMs).sort((a, b) => a - b); + const startSec = starts[0] / 1000; + const endSec = percentile(ends, 0.95) / 1000; + if (startSec >= 0 && startSec <= 12) { + areas.push({ xStart: Math.max(0, startSec), xEnd: Math.min(12, endSec), color, opacity: 0.1 }); + } + } else { + const times = events.map(e => e.timeMs).sort((a, b) => a - b); + const minSec = times[0] / 1000; + const p95Sec = percentile(times, 0.95) / 1000; + if (minSec >= 0 && p95Sec <= 12) { + const width = p95Sec - minSec; + if (width < MIN_AREA_WIDTH_SEC) { + const medSec = percentile(times, 0.5) / 1000; + areas.push({ + xStart: medSec - MIN_AREA_WIDTH_SEC / 2, + xEnd: medSec + MIN_AREA_WIDTH_SEC / 2, + color, + opacity: 0.25, + }); + } else { + areas.push({ xStart: minSec, xEnd: p95Sec, color, opacity: 0.1 }); + } + } + } + } + } + + return areas; + }, [annotations, enabledAnnotations, selectedNode]); + + const markLines = useMemo((): MarkLineConfig[] => { + if (!enabledAnnotations.has('slot_phases')) return []; + + const lines: MarkLineConfig[] = []; + let cumulativeSec = 0; + + for (let i = 0; i < DEFAULT_BEACON_SLOT_PHASES.length - 1; i++) { + cumulativeSec += DEFAULT_BEACON_SLOT_PHASES[i].duration / 1000; + const nextPhase = DEFAULT_BEACON_SLOT_PHASES[i + 1]; + const color = PHASE_BOUNDARY_COLORS[i + 1] ?? '#6b7280'; + + lines.push({ + xValue: cumulativeSec, + label: nextPhase.label, + labelPosition: 'insideEndTop', + color, + lineStyle: 'dotted', + lineWidth: 1, + distance: [0, -8], + }); + } + + return lines; + }, [enabledAnnotations]); + + const nodeCount = new Set(data.map(d => d.meta_client_name)).size; + const shortNodeName = selectedNode?.split('/').pop() ?? ''; + + const subtitle = selectedNode + ? `Slot ${slot} · ${shortNodeName} · ${METRIC_LABELS[metric]}` + : `Slot ${slot} · Mean across ${nodeCount} nodes · ${METRIC_LABELS[metric]}`; + + const headerActions = selectedNode ? ( + clClient || elClient ? ( +
+ {clClient && } + {elClient && } +
+ ) : undefined + ) : ( + + ); + + if (data.length === 0) { + return ( + + {({ inModal }) => ( +
+
+

No memory usage data available for this slot

+
+
+ )} +
+ ); + } + + return ( + + {({ inModal }) => ( + `${v}s`, + }} + yAxis={{ + name: 'MB', + min: 0, + formatter: (v: number) => `${v.toFixed(0)} MB`, + }} + height={inModal ? 500 : 350} + showLegend + legendPosition="bottom" + markLines={markLines} + markAreas={markAreas} + syncGroup="slot-time" + tooltipFormatter={(params: unknown) => { + const items = (Array.isArray(params) ? params : [params]) as EChartsTooltipParam[]; + if (items.length === 0) return ''; + + const first = items[0]; + const xVal = Array.isArray(first.value) ? first.value[0] : first.axisValue; + const timeStr = typeof xVal === 'number' ? `${xVal.toFixed(2)}s` : `${xVal}s`; + + let html = `
`; + html += `
${timeStr}
`; + + for (const p of items) { + const val = Array.isArray(p.value) ? p.value[1] : p.value; + if (val == null) continue; + html += `
`; + html += `${p.marker}`; + html += `${p.seriesName}`; + html += `${Number(val).toFixed(1)} MB`; + html += `
`; + } + + html += `
`; + return html; + }} + /> + )} +
+ ); +} diff --git a/src/pages/ethereum/slots/components/NodeResources/NetworkIoChart.tsx b/src/pages/ethereum/slots/components/NodeResources/NetworkIoChart.tsx new file mode 100644 index 000000000..2ebdd7613 --- /dev/null +++ b/src/pages/ethereum/slots/components/NodeResources/NetworkIoChart.tsx @@ -0,0 +1,296 @@ +import { type JSX, useMemo } from 'react'; +import { PopoutCard } from '@/components/Layout/PopoutCard'; +import { MultiLineChart } from '@/components/Charts/MultiLine'; +import type { SeriesData, MarkAreaConfig, MarkLineConfig } from '@/components/Charts/MultiLine/MultiLine.types'; +import { getDataVizColors } from '@/utils'; +import { DEFAULT_BEACON_SLOT_PHASES } from '@/utils/beacon'; +import type { FctNodeNetworkIoByProcess } from '@/api/types.gen'; +import { ANNOTATION_COLORS, type AnnotationType, type AnnotationEvent } from './types'; + +function usToSeconds(us: number): number { + return us / 1_000_000; +} + +function bytesToKB(bytes: number): number { + return bytes / 1024; +} + +/** Port labels that are hidden by default (internal/API traffic) */ +const HIDDEN_PORTS = new Set(['cl_beacon_api', 'el_json_rpc', 'el_engine_api', 'el_ws', 'cl_grpc']); + +const PORT_LABELS: Record = { + el_p2p_tcp: 'EL P2P', + cl_p2p_tcp: 'CL P2P', + cl_discovery: 'CL Discovery', + el_discovery: 'EL Discovery', + cl_beacon_api: 'CL Beacon API', + el_json_rpc: 'EL JSON-RPC', + el_engine_api: 'EL Engine API', + el_ws: 'EL WebSocket', + cl_grpc: 'CL gRPC', + unknown: 'Unknown', +}; + +const MIN_AREA_WIDTH_SEC = 0.08; + +function nodeMatches(cpuNodeName: string, propNodeId: string): boolean { + const short = cpuNodeName.split('/').pop() ?? cpuNodeName; + return propNodeId === short || propNodeId === cpuNodeName || short.includes(propNodeId) || propNodeId.includes(short); +} + +function percentile(sorted: number[], p: number): number { + const idx = Math.floor(sorted.length * p); + return sorted[Math.min(idx, sorted.length - 1)]; +} + +const BUCKET_SIZE = 0.25; +const toBucket = (offsetSec: number): number => Math.round(offsetSec / BUCKET_SIZE) * BUCKET_SIZE; +const avg = (arr: number[]): number => arr.reduce((s, v) => s + v, 0) / arr.length; + +interface NetworkIoChartProps { + data: FctNodeNetworkIoByProcess[]; + selectedNode: string | null; + slot: number; + annotations: AnnotationEvent[]; + enabledAnnotations: Set; +} + +const PHASE_BOUNDARY_COLORS = ['#22d3ee', '#22c55e', '#f59e0b']; + +interface EChartsTooltipParam { + marker: string; + seriesName: string; + value: [number, number] | number; + axisValue?: number | string; +} + +export function NetworkIoChart({ + data, + selectedNode, + slot, + annotations, + enabledAnnotations, +}: NetworkIoChartProps): JSX.Element { + const { CHART_CATEGORICAL_COLORS } = getDataVizColors(); + + const series = useMemo(() => { + if (data.length === 0) return [] as SeriesData[]; + + const slotStartUs = Math.min(...data.map(d => d.wallclock_slot_start_date_time ?? 0).filter(v => v > 0)); + const chartSeries: SeriesData[] = []; + + // Group by port_label, aggregate tx+rx bytes per bucket + const ports = new Set(data.map(d => d.port_label).filter(Boolean) as string[]); + const sortedPorts = Array.from(ports).sort(); + + for (let i = 0; i < sortedPorts.length; i++) { + const port = sortedPorts[i]; + const portData = data.filter(d => d.port_label === port); + + let filteredPortData = portData; + if (selectedNode) { + filteredPortData = portData.filter(d => d.meta_client_name === selectedNode); + } + + // Bucket and aggregate tx+rx bytes + const buckets = new Map(); + for (const d of filteredPortData) { + const offset = usToSeconds((d.window_start ?? 0) - slotStartUs); + const bucket = toBucket(offset); + if (bucket < 0 || bucket > 12) continue; + + if (!buckets.has(bucket)) buckets.set(bucket, []); + buckets.get(bucket)!.push(bytesToKB(d.io_bytes ?? 0)); + } + + const points: [number, number][] = Array.from(buckets.entries()) + .sort(([a], [b]) => a - b) + .map(([t, vals]) => [t, avg(vals)] as [number, number]); + + if (points.length === 0) continue; + + const label = PORT_LABELS[port] ?? port; + const color = CHART_CATEGORICAL_COLORS[i % CHART_CATEGORICAL_COLORS.length]; + + chartSeries.push({ + name: label, + data: points, + color, + lineWidth: 2, + showArea: true, + areaOpacity: 0.06, + initiallyVisible: !HIDDEN_PORTS.has(port), + }); + } + + return chartSeries; + }, [data, selectedNode, CHART_CATEGORICAL_COLORS]); + + const markAreas = useMemo((): MarkAreaConfig[] => { + const areas: MarkAreaConfig[] = []; + + if (selectedNode) { + for (const anno of annotations) { + if (!enabledAnnotations.has(anno.type)) continue; + if (!anno.nodeName || !nodeMatches(selectedNode, anno.nodeName)) continue; + + const startSec = anno.timeMs / 1000; + if (startSec < 0 || startSec > 12) continue; + const color = ANNOTATION_COLORS[anno.type]; + const hasRange = anno.endMs != null && Math.abs(anno.endMs - anno.timeMs) > 10; + + if (hasRange) { + const endSec = Math.min(anno.endMs! / 1000, 12); + areas.push({ xStart: startSec, xEnd: endSec, color, opacity: 0.12 }); + } else { + areas.push({ + xStart: startSec - MIN_AREA_WIDTH_SEC / 2, + xEnd: startSec + MIN_AREA_WIDTH_SEC / 2, + color, + opacity: 0.3, + }); + } + } + } else { + const byType = new Map(); + for (const anno of annotations) { + if (!enabledAnnotations.has(anno.type)) continue; + if (!byType.has(anno.type)) byType.set(anno.type, []); + byType.get(anno.type)!.push(anno); + } + + for (const [type, events] of byType) { + const color = ANNOTATION_COLORS[type]; + const hasRanges = events.some(e => e.endMs != null); + + if (hasRanges) { + const starts = events.map(e => e.timeMs).sort((a, b) => a - b); + const ends = events.map(e => e.endMs ?? e.timeMs).sort((a, b) => a - b); + const startSec = starts[0] / 1000; + const endSec = percentile(ends, 0.95) / 1000; + if (startSec >= 0 && startSec <= 12) { + areas.push({ xStart: Math.max(0, startSec), xEnd: Math.min(12, endSec), color, opacity: 0.1 }); + } + } else { + const times = events.map(e => e.timeMs).sort((a, b) => a - b); + const minSec = times[0] / 1000; + const p95Sec = percentile(times, 0.95) / 1000; + if (minSec >= 0 && p95Sec <= 12) { + const width = p95Sec - minSec; + if (width < MIN_AREA_WIDTH_SEC) { + const medSec = percentile(times, 0.5) / 1000; + areas.push({ + xStart: medSec - MIN_AREA_WIDTH_SEC / 2, + xEnd: medSec + MIN_AREA_WIDTH_SEC / 2, + color, + opacity: 0.25, + }); + } else { + areas.push({ xStart: minSec, xEnd: p95Sec, color, opacity: 0.1 }); + } + } + } + } + } + + return areas; + }, [annotations, enabledAnnotations, selectedNode]); + + const markLines = useMemo((): MarkLineConfig[] => { + if (!enabledAnnotations.has('slot_phases')) return []; + + const lines: MarkLineConfig[] = []; + let cumulativeSec = 0; + + for (let i = 0; i < DEFAULT_BEACON_SLOT_PHASES.length - 1; i++) { + cumulativeSec += DEFAULT_BEACON_SLOT_PHASES[i].duration / 1000; + const nextPhase = DEFAULT_BEACON_SLOT_PHASES[i + 1]; + const color = PHASE_BOUNDARY_COLORS[i + 1] ?? '#6b7280'; + + lines.push({ + xValue: cumulativeSec, + label: nextPhase.label, + labelPosition: 'insideEndTop', + color, + lineStyle: 'dotted', + lineWidth: 1, + distance: [0, -8], + }); + } + + return lines; + }, [enabledAnnotations]); + + const nodeCount = new Set(data.map(d => d.meta_client_name)).size; + const shortNodeName = selectedNode?.split('/').pop() ?? ''; + + const subtitle = selectedNode + ? `Slot ${slot} · ${shortNodeName} · Network traffic by port` + : `Slot ${slot} · Mean across ${nodeCount} nodes · Network traffic by port`; + + if (data.length === 0) { + return ( + + {({ inModal }) => ( +
+
+

No network I/O data available for this slot

+
+
+ )} +
+ ); + } + + return ( + + {({ inModal }) => ( + `${v}s`, + }} + yAxis={{ + name: 'KB', + min: 0, + formatter: (v: number) => `${v.toFixed(0)} KB`, + }} + height={inModal ? 500 : 350} + showLegend + legendPosition="bottom" + markLines={markLines} + markAreas={markAreas} + syncGroup="slot-time" + tooltipFormatter={(params: unknown) => { + const items = (Array.isArray(params) ? params : [params]) as EChartsTooltipParam[]; + if (items.length === 0) return ''; + + const first = items[0]; + const xVal = Array.isArray(first.value) ? first.value[0] : first.axisValue; + const timeStr = typeof xVal === 'number' ? `${xVal.toFixed(2)}s` : `${xVal}s`; + + let html = `
`; + html += `
${timeStr}
`; + + for (const p of items) { + const val = Array.isArray(p.value) ? p.value[1] : p.value; + if (val == null) continue; + html += `
`; + html += `${p.marker}`; + html += `${p.seriesName}`; + html += `${Number(val).toFixed(1)} KB`; + html += `
`; + } + + html += `
`; + return html; + }} + /> + )} +
+ ); +} diff --git a/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx b/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx index b7d1e4b73..f5fb94523 100644 --- a/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx @@ -14,18 +14,33 @@ import type { FctBlockDataColumnSidecarFirstSeenByNode, } from '@/api/types.gen'; import { useSlotNodeResources } from '../../hooks/useSlotNodeResources'; +import { useSlotNodeMemory } from '../../hooks/useSlotNodeMemory'; +import { useSlotNodeDiskIo } from '../../hooks/useSlotNodeDiskIo'; +import { useSlotNodeNetworkIo } from '../../hooks/useSlotNodeNetworkIo'; import { NodeSelector, type NodeClientInfo } from './NodeSelector'; import { CpuUtilizationChart } from './CpuUtilizationChart'; +import { MemoryUsageChart } from './MemoryUsageChart'; +import { DiskIoChart } from './DiskIoChart'; +import { NetworkIoChart } from './NetworkIoChart'; import { ANNOTATION_OPTIONS, ANNOTATION_COLORS, type CpuMetric, + type MemoryMetric, + type ResourceTab, type AnnotationType, type AnnotationEvent, } from './types'; export type { CpuMetric } from './types'; +const RESOURCE_TABS: { value: ResourceTab; label: string }[] = [ + { value: 'cpu', label: 'CPU' }, + { value: 'memory', label: 'Memory' }, + { value: 'disk', label: 'Disk I/O' }, + { value: 'network', label: 'Network' }, +]; + function nodeMatches(cpuNodeName: string, eventNodeName: string): boolean { const short = cpuNodeName.split('/').pop() ?? cpuNodeName; return ( @@ -49,7 +64,11 @@ export function NodeResourcesPanel({ headPropagation, dataColumnPropagation, }: NodeResourcesPanelProps): JSX.Element { - const { data, isLoading, error } = useSlotNodeResources(slot); + const { data: cpuData, isLoading: cpuLoading, error: cpuError } = useSlotNodeResources(slot); + const { data: memoryData } = useSlotNodeMemory(slot); + const { data: diskData } = useSlotNodeDiskIo(slot); + const { data: networkData } = useSlotNodeNetworkIo(slot); + const search = useSearch({ from: '/ethereum/slots/$slot' }); const navigate = useNavigate(); const [showRefNodeInfo, setShowRefNodeInfo] = useState(false); @@ -71,6 +90,8 @@ export function NodeResourcesPanel({ const referenceNodesOnly = search.refNodes ?? false; const selectedNode = search.node ?? null; const metric: CpuMetric = search.metric ?? 'mean'; + const memMetric: MemoryMetric = search.memMetric ?? 'vm_rss'; + const resourceTab: ResourceTab = search.resourceTab ?? 'cpu'; const setReferenceNodesOnly = useCallback( (value: boolean) => { @@ -111,6 +132,32 @@ export function NodeResourcesPanel({ [navigate, slot, search] ); + const setMemMetric = useCallback( + (value: MemoryMetric) => { + navigate({ + to: '/ethereum/slots/$slot', + params: { slot: String(slot) }, + search: { ...search, memMetric: value === 'vm_rss' ? undefined : value }, + replace: true, + resetScroll: false, + }); + }, + [navigate, slot, search] + ); + + const setResourceTab = useCallback( + (value: ResourceTab) => { + navigate({ + to: '/ethereum/slots/$slot', + params: { slot: String(slot) }, + search: { ...search, resourceTab: value === 'cpu' ? undefined : value }, + replace: true, + resetScroll: false, + }); + }, + [navigate, slot, search] + ); + const toggleAnnotation = useCallback((type: AnnotationType) => { setEnabledAnnotations(prev => { const next = new Set(prev); @@ -123,25 +170,49 @@ export function NodeResourcesPanel({ }); }, []); - // Filter data based on reference nodes toggle - const filteredData = useMemo(() => { - if (!data) return []; - if (!referenceNodesOnly) return data; - return data.filter( + // Filter CPU data based on reference nodes toggle + const filteredCpuData = useMemo(() => { + if (!cpuData) return []; + if (!referenceNodesOnly) return cpuData; + return cpuData.filter( + d => d.node_class === 'eip7870' || extractClusterFromNodeName(d.meta_client_name ?? '') !== null + ); + }, [cpuData, referenceNodesOnly]); + + const filteredMemoryData = useMemo(() => { + if (!memoryData) return []; + if (!referenceNodesOnly) return memoryData; + return memoryData.filter( + d => d.node_class === 'eip7870' || extractClusterFromNodeName(d.meta_client_name ?? '') !== null + ); + }, [memoryData, referenceNodesOnly]); + + const filteredDiskData = useMemo(() => { + if (!diskData) return []; + if (!referenceNodesOnly) return diskData; + return diskData.filter( d => d.node_class === 'eip7870' || extractClusterFromNodeName(d.meta_client_name ?? '') !== null ); - }, [data, referenceNodesOnly]); + }, [diskData, referenceNodesOnly]); - // Get unique node names from filtered data + const filteredNetworkData = useMemo(() => { + if (!networkData) return []; + if (!referenceNodesOnly) return networkData; + return networkData.filter( + d => d.node_class === 'eip7870' || extractClusterFromNodeName(d.meta_client_name ?? '') !== null + ); + }, [networkData, referenceNodesOnly]); + + // Get unique node names from CPU data (primary source for node selector) const nodeNames = useMemo(() => { - const names = new Set(filteredData.map(d => d.meta_client_name).filter(Boolean) as string[]); + const names = new Set(filteredCpuData.map(d => d.meta_client_name).filter(Boolean) as string[]); return Array.from(names).sort(); - }, [filteredData]); + }, [filteredCpuData]); - // Build node → {cl, el} client info map from the data + // Build node → {cl, el} client info map from the CPU data const nodeClientInfo = useMemo(() => { const info = new Map(); - for (const d of filteredData) { + for (const d of filteredCpuData) { const name = d.meta_client_name; const clientType = d.client_type?.toLowerCase() ?? ''; if (!name) continue; @@ -157,7 +228,7 @@ export function NodeResourcesPanel({ info.set(name, existing); } return info; - }, [filteredData]); + }, [filteredCpuData]); // Reset selected node if it's no longer in the filtered list const effectiveSelectedNode = selectedNode && nodeNames.includes(selectedNode) ? selectedNode : null; @@ -235,12 +306,12 @@ export function NodeResourcesPanel({ return ANNOTATION_OPTIONS.filter(o => o.value === 'slot_phases' || types.has(o.value)); }, [annotations]); - if (isLoading) { + if (cpuLoading) { return (

Node Resources

-

CPU utilization from observoor eBPF agent

+

Resource metrics from observoor eBPF agent

@@ -250,17 +321,17 @@ export function NodeResourcesPanel({ ); } - if (error) { + if (cpuError) { return (
-

Failed to load node resource data: {error.message}

+

Failed to load node resource data: {cpuError.message}

); } - if (!data || data.length === 0) { + if (!cpuData || cpuData.length === 0) { return (
@@ -318,10 +389,26 @@ export function NodeResourcesPanel({
+ {/* Resource type tabs */} +
+ {RESOURCE_TABS.map(tab => ( + + ))} +
+ {/* Annotation toggles */} {availableAnnotations.length > 0 && (
- Annotations{!effectiveSelectedNode && ' (min–p95)'}: + Annotations{!effectiveSelectedNode && ' (min\u2013p95)'}: {availableAnnotations.map(opt => (
diff --git a/src/pages/ethereum/slots/components/NodeResources/types.ts b/src/pages/ethereum/slots/components/NodeResources/types.ts index 5c4c2f473..21ce603e4 100644 --- a/src/pages/ethereum/slots/components/NodeResources/types.ts +++ b/src/pages/ethereum/slots/components/NodeResources/types.ts @@ -1,5 +1,9 @@ export type CpuMetric = 'mean' | 'min' | 'max'; +export type MemoryMetric = 'vm_rss' | 'rss_anon' | 'rss_file' | 'vm_swap'; + +export type ResourceTab = 'cpu' | 'memory' | 'disk' | 'network'; + export type AnnotationType = 'block' | 'head' | 'execution' | 'data_columns' | 'slot_phases'; export interface AnnotationEvent { diff --git a/src/pages/ethereum/slots/hooks/useSlotNodeDiskIo/index.ts b/src/pages/ethereum/slots/hooks/useSlotNodeDiskIo/index.ts new file mode 100644 index 000000000..0ed13cb91 --- /dev/null +++ b/src/pages/ethereum/slots/hooks/useSlotNodeDiskIo/index.ts @@ -0,0 +1,2 @@ +export { useSlotNodeDiskIo } from './useSlotNodeDiskIo'; +export type { UseSlotNodeDiskIoResult } from './useSlotNodeDiskIo'; diff --git a/src/pages/ethereum/slots/hooks/useSlotNodeDiskIo/useSlotNodeDiskIo.ts b/src/pages/ethereum/slots/hooks/useSlotNodeDiskIo/useSlotNodeDiskIo.ts new file mode 100644 index 000000000..9c95acedf --- /dev/null +++ b/src/pages/ethereum/slots/hooks/useSlotNodeDiskIo/useSlotNodeDiskIo.ts @@ -0,0 +1,35 @@ +import { useQuery } from '@tanstack/react-query'; +import { fctNodeDiskIoByProcessServiceListOptions } from '@/api/@tanstack/react-query.gen'; +import { useNetwork } from '@/hooks/useNetwork'; +import { slotToTimestamp } from '@/utils/beacon'; +import type { FctNodeDiskIoByProcess } from '@/api/types.gen'; + +const SECONDS_TO_MICROSECONDS = 1_000_000; + +export interface UseSlotNodeDiskIoResult { + data: FctNodeDiskIoByProcess[] | null; + isLoading: boolean; + error: Error | null; +} + +export function useSlotNodeDiskIo(slot: number): UseSlotNodeDiskIoResult { + const { currentNetwork } = useNetwork(); + const slotTimestamp = currentNetwork ? slotToTimestamp(slot, currentNetwork.genesis_time) : 0; + const slotTimestampUs = slotTimestamp * SECONDS_TO_MICROSECONDS; + + const { data, isLoading, error } = useQuery({ + ...fctNodeDiskIoByProcessServiceListOptions({ + query: { + wallclock_slot_start_date_time_eq: slotTimestampUs, + page_size: 10000, + }, + }), + enabled: !!currentNetwork && slotTimestamp > 0, + }); + + return { + data: data?.fct_node_disk_io_by_process ?? null, + isLoading, + error: error as Error | null, + }; +} diff --git a/src/pages/ethereum/slots/hooks/useSlotNodeMemory/index.ts b/src/pages/ethereum/slots/hooks/useSlotNodeMemory/index.ts new file mode 100644 index 000000000..2a8d2fc67 --- /dev/null +++ b/src/pages/ethereum/slots/hooks/useSlotNodeMemory/index.ts @@ -0,0 +1,2 @@ +export { useSlotNodeMemory } from './useSlotNodeMemory'; +export type { UseSlotNodeMemoryResult } from './useSlotNodeMemory'; diff --git a/src/pages/ethereum/slots/hooks/useSlotNodeMemory/useSlotNodeMemory.ts b/src/pages/ethereum/slots/hooks/useSlotNodeMemory/useSlotNodeMemory.ts new file mode 100644 index 000000000..67a569e25 --- /dev/null +++ b/src/pages/ethereum/slots/hooks/useSlotNodeMemory/useSlotNodeMemory.ts @@ -0,0 +1,35 @@ +import { useQuery } from '@tanstack/react-query'; +import { fctNodeMemoryUsageByProcessServiceListOptions } from '@/api/@tanstack/react-query.gen'; +import { useNetwork } from '@/hooks/useNetwork'; +import { slotToTimestamp } from '@/utils/beacon'; +import type { FctNodeMemoryUsageByProcess } from '@/api/types.gen'; + +const SECONDS_TO_MICROSECONDS = 1_000_000; + +export interface UseSlotNodeMemoryResult { + data: FctNodeMemoryUsageByProcess[] | null; + isLoading: boolean; + error: Error | null; +} + +export function useSlotNodeMemory(slot: number): UseSlotNodeMemoryResult { + const { currentNetwork } = useNetwork(); + const slotTimestamp = currentNetwork ? slotToTimestamp(slot, currentNetwork.genesis_time) : 0; + const slotTimestampUs = slotTimestamp * SECONDS_TO_MICROSECONDS; + + const { data, isLoading, error } = useQuery({ + ...fctNodeMemoryUsageByProcessServiceListOptions({ + query: { + wallclock_slot_start_date_time_eq: slotTimestampUs, + page_size: 10000, + }, + }), + enabled: !!currentNetwork && slotTimestamp > 0, + }); + + return { + data: data?.fct_node_memory_usage_by_process ?? null, + isLoading, + error: error as Error | null, + }; +} diff --git a/src/pages/ethereum/slots/hooks/useSlotNodeNetworkIo/index.ts b/src/pages/ethereum/slots/hooks/useSlotNodeNetworkIo/index.ts new file mode 100644 index 000000000..f8e739b79 --- /dev/null +++ b/src/pages/ethereum/slots/hooks/useSlotNodeNetworkIo/index.ts @@ -0,0 +1,2 @@ +export { useSlotNodeNetworkIo } from './useSlotNodeNetworkIo'; +export type { UseSlotNodeNetworkIoResult } from './useSlotNodeNetworkIo'; diff --git a/src/pages/ethereum/slots/hooks/useSlotNodeNetworkIo/useSlotNodeNetworkIo.ts b/src/pages/ethereum/slots/hooks/useSlotNodeNetworkIo/useSlotNodeNetworkIo.ts new file mode 100644 index 000000000..77afd0350 --- /dev/null +++ b/src/pages/ethereum/slots/hooks/useSlotNodeNetworkIo/useSlotNodeNetworkIo.ts @@ -0,0 +1,35 @@ +import { useQuery } from '@tanstack/react-query'; +import { fctNodeNetworkIoByProcessServiceListOptions } from '@/api/@tanstack/react-query.gen'; +import { useNetwork } from '@/hooks/useNetwork'; +import { slotToTimestamp } from '@/utils/beacon'; +import type { FctNodeNetworkIoByProcess } from '@/api/types.gen'; + +const SECONDS_TO_MICROSECONDS = 1_000_000; + +export interface UseSlotNodeNetworkIoResult { + data: FctNodeNetworkIoByProcess[] | null; + isLoading: boolean; + error: Error | null; +} + +export function useSlotNodeNetworkIo(slot: number): UseSlotNodeNetworkIoResult { + const { currentNetwork } = useNetwork(); + const slotTimestamp = currentNetwork ? slotToTimestamp(slot, currentNetwork.genesis_time) : 0; + const slotTimestampUs = slotTimestamp * SECONDS_TO_MICROSECONDS; + + const { data, isLoading, error } = useQuery({ + ...fctNodeNetworkIoByProcessServiceListOptions({ + query: { + wallclock_slot_start_date_time_eq: slotTimestampUs, + page_size: 10000, + }, + }), + enabled: !!currentNetwork && slotTimestamp > 0, + }); + + return { + data: data?.fct_node_network_io_by_process ?? null, + isLoading, + error: error as Error | null, + }; +} diff --git a/src/routes/ethereum/slots/$slot.tsx b/src/routes/ethereum/slots/$slot.tsx index 455442cdd..6dcddd967 100644 --- a/src/routes/ethereum/slots/$slot.tsx +++ b/src/routes/ethereum/slots/$slot.tsx @@ -9,6 +9,8 @@ const slotSearchSchema = z.object({ contributor: z.string().optional(), node: z.string().optional(), metric: z.enum(['mean', 'min', 'max']).optional(), + memMetric: z.enum(['vm_rss', 'rss_anon', 'rss_file', 'vm_swap']).optional(), + resourceTab: z.enum(['cpu', 'memory', 'disk', 'network']).optional(), refNodes: z.coerce.boolean().optional(), }); From 02c41fc267e8002b95923c1e2d134c07978340ac Mon Sep 17 00:00:00 2001 From: Sam Calder-Mason Date: Thu, 12 Feb 2026 21:51:56 +1000 Subject: [PATCH 10/15] Show all 4 resource charts in 2x2 grid, add smoothing and zero-padding Replace tab-based switching with a 2-column grid showing CPU, Memory, Disk I/O, and Network charts simultaneously. Zero-pad all 250ms buckets so charts show continuous lines (no gaps in quiet periods). Add smooth curve interpolation (0.4) to all series for cleaner visualization. --- .../NodeResources/CpuUtilizationChart.tsx | 11 ++-- .../components/NodeResources/DiskIoChart.tsx | 11 ++-- .../NodeResources/MemoryUsageChart.tsx | 9 ++-- .../NodeResources/NetworkIoChart.tsx | 10 ++-- .../NodeResources/NodeResourcesPanel.tsx | 53 ++----------------- .../slots/components/NodeResources/types.ts | 2 - src/routes/ethereum/slots/$slot.tsx | 1 - 7 files changed, 31 insertions(+), 66 deletions(-) diff --git a/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx b/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx index b46eeb081..a76d14333 100644 --- a/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx @@ -76,6 +76,7 @@ interface EChartsTooltipParam { } const BUCKET_SIZE = 0.25; +const ALL_BUCKETS = Array.from({ length: 49 }, (_, i) => i * BUCKET_SIZE); const toBucket = (offsetSec: number): number => Math.round(offsetSec / BUCKET_SIZE) * BUCKET_SIZE; const avg = (arr: number[]): number => arr.reduce((s, v) => s + v, 0) / arr.length; @@ -121,9 +122,7 @@ export function CpuUtilizationChart({ }; const toPoints = (buckets: Map, extract: (b: BucketAgg) => number[]): [number, number][] => - Array.from(buckets.entries()) - .sort(([a], [b]) => a - b) - .map(([t, b]) => [t, avg(extract(b))] as [number, number]); + ALL_BUCKETS.map(t => [t, buckets.has(t) ? avg(extract(buckets.get(t)!)) : 0] as [number, number]); const metricExtract = (b: BucketAgg): number[] => { switch (metric) { @@ -160,6 +159,7 @@ export function CpuUtilizationChart({ lineWidth: 2, showArea: true, areaOpacity: 0.08, + smooth: 0.4, }); chartSeries.push({ @@ -169,6 +169,7 @@ export function CpuUtilizationChart({ lineWidth: 2, showArea: true, areaOpacity: 0.08, + smooth: 0.4, }); chartSeries.push({ @@ -179,6 +180,7 @@ export function CpuUtilizationChart({ lineStyle: 'dashed', showArea: false, initiallyVisible: false, + smooth: 0.4, }); chartSeries.push({ name: `${elLabel} peak core`, @@ -188,6 +190,7 @@ export function CpuUtilizationChart({ lineStyle: 'dashed', showArea: false, initiallyVisible: false, + smooth: 0.4, }); } else { const clData = data.filter(d => getClientLayer(d.client_type ?? '') === 'CL'); @@ -203,6 +206,7 @@ export function CpuUtilizationChart({ lineWidth: 2, showArea: true, areaOpacity: 0.08, + smooth: 0.4, }); chartSeries.push({ @@ -212,6 +216,7 @@ export function CpuUtilizationChart({ lineWidth: 2, showArea: true, areaOpacity: 0.08, + smooth: 0.4, }); } diff --git a/src/pages/ethereum/slots/components/NodeResources/DiskIoChart.tsx b/src/pages/ethereum/slots/components/NodeResources/DiskIoChart.tsx index c688d6a86..91c91414c 100644 --- a/src/pages/ethereum/slots/components/NodeResources/DiskIoChart.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/DiskIoChart.tsx @@ -33,6 +33,7 @@ function percentile(sorted: number[], p: number): number { } const BUCKET_SIZE = 0.25; +const ALL_BUCKETS = Array.from({ length: 49 }, (_, i) => i * BUCKET_SIZE); const toBucket = (offsetSec: number): number => Math.round(offsetSec / BUCKET_SIZE) * BUCKET_SIZE; const avg = (arr: number[]): number => arr.reduce((s, v) => s + v, 0) / arr.length; @@ -86,9 +87,7 @@ export function DiskIoChart({ }; const toPoints = (buckets: Map): [number, number][] => - Array.from(buckets.entries()) - .sort(([a], [b]) => a - b) - .map(([t, vals]) => [t, avg(vals)] as [number, number]); + ALL_BUCKETS.map(t => [t, buckets.has(t) ? avg(buckets.get(t)!) : 0] as [number, number]); if (selectedNode) { const nodeData = data.filter(d => d.meta_client_name === selectedNode); @@ -113,6 +112,7 @@ export function DiskIoChart({ lineWidth: 2, showArea: true, areaOpacity: 0.08, + smooth: 0.4, }); chartSeries.push({ name: `${clLabel} Write`, @@ -121,6 +121,7 @@ export function DiskIoChart({ lineWidth: 1.5, lineStyle: 'dashed', showArea: false, + smooth: 0.4, }); chartSeries.push({ name: `${elLabel} Read`, @@ -129,6 +130,7 @@ export function DiskIoChart({ lineWidth: 2, showArea: true, areaOpacity: 0.08, + smooth: 0.4, }); chartSeries.push({ name: `${elLabel} Write`, @@ -137,6 +139,7 @@ export function DiskIoChart({ lineWidth: 1.5, lineStyle: 'dashed', showArea: false, + smooth: 0.4, }); } else { const readData = data.filter(d => d.rw === 'read'); @@ -149,6 +152,7 @@ export function DiskIoChart({ lineWidth: 2, showArea: true, areaOpacity: 0.08, + smooth: 0.4, }); chartSeries.push({ name: 'Write', @@ -157,6 +161,7 @@ export function DiskIoChart({ lineWidth: 2, showArea: true, areaOpacity: 0.08, + smooth: 0.4, }); } diff --git a/src/pages/ethereum/slots/components/NodeResources/MemoryUsageChart.tsx b/src/pages/ethereum/slots/components/NodeResources/MemoryUsageChart.tsx index 450a1d64a..d51de2355 100644 --- a/src/pages/ethereum/slots/components/NodeResources/MemoryUsageChart.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/MemoryUsageChart.tsx @@ -50,6 +50,7 @@ function percentile(sorted: number[], p: number): number { } const BUCKET_SIZE = 0.25; +const ALL_BUCKETS = Array.from({ length: 49 }, (_, i) => i * BUCKET_SIZE); const toBucket = (offsetSec: number): number => Math.round(offsetSec / BUCKET_SIZE) * BUCKET_SIZE; const avg = (arr: number[]): number => arr.reduce((s, v) => s + v, 0) / arr.length; @@ -120,9 +121,7 @@ export function MemoryUsageChart({ }; const toPoints = (buckets: Map): [number, number][] => - Array.from(buckets.entries()) - .sort(([a], [b]) => a - b) - .map(([t, vals]) => [t, avg(vals)] as [number, number]); + ALL_BUCKETS.map(t => [t, buckets.has(t) ? avg(buckets.get(t)!) : 0] as [number, number]); if (selectedNode) { const nodeData = data.filter(d => d.meta_client_name === selectedNode); @@ -139,6 +138,7 @@ export function MemoryUsageChart({ lineWidth: 2, showArea: true, areaOpacity: 0.08, + smooth: 0.4, }); chartSeries.push({ @@ -148,6 +148,7 @@ export function MemoryUsageChart({ lineWidth: 2, showArea: true, areaOpacity: 0.08, + smooth: 0.4, }); } else { const clData = data.filter(d => getClientLayer(d.client_type ?? '') === 'CL'); @@ -160,6 +161,7 @@ export function MemoryUsageChart({ lineWidth: 2, showArea: true, areaOpacity: 0.08, + smooth: 0.4, }); chartSeries.push({ @@ -169,6 +171,7 @@ export function MemoryUsageChart({ lineWidth: 2, showArea: true, areaOpacity: 0.08, + smooth: 0.4, }); } diff --git a/src/pages/ethereum/slots/components/NodeResources/NetworkIoChart.tsx b/src/pages/ethereum/slots/components/NodeResources/NetworkIoChart.tsx index 2ebdd7613..992b4d012 100644 --- a/src/pages/ethereum/slots/components/NodeResources/NetworkIoChart.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/NetworkIoChart.tsx @@ -44,6 +44,7 @@ function percentile(sorted: number[], p: number): number { } const BUCKET_SIZE = 0.25; +const ALL_BUCKETS = Array.from({ length: 49 }, (_, i) => i * BUCKET_SIZE); const toBucket = (offsetSec: number): number => Math.round(offsetSec / BUCKET_SIZE) * BUCKET_SIZE; const avg = (arr: number[]): number => arr.reduce((s, v) => s + v, 0) / arr.length; @@ -103,11 +104,11 @@ export function NetworkIoChart({ buckets.get(bucket)!.push(bytesToKB(d.io_bytes ?? 0)); } - const points: [number, number][] = Array.from(buckets.entries()) - .sort(([a], [b]) => a - b) - .map(([t, vals]) => [t, avg(vals)] as [number, number]); + if (buckets.size === 0) continue; - if (points.length === 0) continue; + const points: [number, number][] = ALL_BUCKETS.map( + t => [t, buckets.has(t) ? avg(buckets.get(t)!) : 0] as [number, number] + ); const label = PORT_LABELS[port] ?? port; const color = CHART_CATEGORICAL_COLORS[i % CHART_CATEGORICAL_COLORS.length]; @@ -119,6 +120,7 @@ export function NetworkIoChart({ lineWidth: 2, showArea: true, areaOpacity: 0.06, + smooth: 0.4, initiallyVisible: !HIDDEN_PORTS.has(port), }); } diff --git a/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx b/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx index f5fb94523..dd12bf5cd 100644 --- a/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx @@ -27,20 +27,12 @@ import { ANNOTATION_COLORS, type CpuMetric, type MemoryMetric, - type ResourceTab, type AnnotationType, type AnnotationEvent, } from './types'; export type { CpuMetric } from './types'; -const RESOURCE_TABS: { value: ResourceTab; label: string }[] = [ - { value: 'cpu', label: 'CPU' }, - { value: 'memory', label: 'Memory' }, - { value: 'disk', label: 'Disk I/O' }, - { value: 'network', label: 'Network' }, -]; - function nodeMatches(cpuNodeName: string, eventNodeName: string): boolean { const short = cpuNodeName.split('/').pop() ?? cpuNodeName; return ( @@ -91,7 +83,6 @@ export function NodeResourcesPanel({ const selectedNode = search.node ?? null; const metric: CpuMetric = search.metric ?? 'mean'; const memMetric: MemoryMetric = search.memMetric ?? 'vm_rss'; - const resourceTab: ResourceTab = search.resourceTab ?? 'cpu'; const setReferenceNodesOnly = useCallback( (value: boolean) => { @@ -145,19 +136,6 @@ export function NodeResourcesPanel({ [navigate, slot, search] ); - const setResourceTab = useCallback( - (value: ResourceTab) => { - navigate({ - to: '/ethereum/slots/$slot', - params: { slot: String(slot) }, - search: { ...search, resourceTab: value === 'cpu' ? undefined : value }, - replace: true, - resetScroll: false, - }); - }, - [navigate, slot, search] - ); - const toggleAnnotation = useCallback((type: AnnotationType) => { setEnabledAnnotations(prev => { const next = new Set(prev); @@ -389,22 +367,6 @@ export function NodeResourcesPanel({
- {/* Resource type tabs */} -
- {RESOURCE_TABS.map(tab => ( - - ))} -
- {/* Annotation toggles */} {availableAnnotations.length > 0 && (
@@ -428,8 +390,8 @@ export function NodeResourcesPanel({ )} - {/* Charts */} - {resourceTab === 'cpu' && ( + {/* Charts – 2 per row */} +
- )} - - {resourceTab === 'memory' && ( - )} - - {resourceTab === 'disk' && ( - )} - - {resourceTab === 'network' && ( - )} +
setShowRefNodeInfo(false)} />
diff --git a/src/pages/ethereum/slots/components/NodeResources/types.ts b/src/pages/ethereum/slots/components/NodeResources/types.ts index 21ce603e4..a70046e90 100644 --- a/src/pages/ethereum/slots/components/NodeResources/types.ts +++ b/src/pages/ethereum/slots/components/NodeResources/types.ts @@ -2,8 +2,6 @@ export type CpuMetric = 'mean' | 'min' | 'max'; export type MemoryMetric = 'vm_rss' | 'rss_anon' | 'rss_file' | 'vm_swap'; -export type ResourceTab = 'cpu' | 'memory' | 'disk' | 'network'; - export type AnnotationType = 'block' | 'head' | 'execution' | 'data_columns' | 'slot_phases'; export interface AnnotationEvent { diff --git a/src/routes/ethereum/slots/$slot.tsx b/src/routes/ethereum/slots/$slot.tsx index 6dcddd967..a711d0a09 100644 --- a/src/routes/ethereum/slots/$slot.tsx +++ b/src/routes/ethereum/slots/$slot.tsx @@ -10,7 +10,6 @@ const slotSearchSchema = z.object({ node: z.string().optional(), metric: z.enum(['mean', 'min', 'max']).optional(), memMetric: z.enum(['vm_rss', 'rss_anon', 'rss_file', 'vm_swap']).optional(), - resourceTab: z.enum(['cpu', 'memory', 'disk', 'network']).optional(), refNodes: z.coerce.boolean().optional(), }); From 595d2fbb8f1ec707ba78cba666eba1631b1493eb Mon Sep 17 00:00:00 2001 From: Sam Calder-Mason Date: Thu, 12 Feb 2026 21:54:35 +1000 Subject: [PATCH 11/15] Break down Disk I/O by CL/EL in aggregate mode Show CL Read, CL Write, EL Read, EL Write series (matching the single-node view pattern) instead of just Read/Write totals. --- .../components/NodeResources/DiskIoChart.tsx | 35 +++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/pages/ethereum/slots/components/NodeResources/DiskIoChart.tsx b/src/pages/ethereum/slots/components/NodeResources/DiskIoChart.tsx index 91c91414c..88b5d3921 100644 --- a/src/pages/ethereum/slots/components/NodeResources/DiskIoChart.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/DiskIoChart.tsx @@ -142,12 +142,17 @@ export function DiskIoChart({ smooth: 0.4, }); } else { - const readData = data.filter(d => d.rw === 'read'); - const writeData = data.filter(d => d.rw === 'write'); + const clData = data.filter(d => getClientLayer(d.client_type ?? '') === 'CL'); + const elData = data.filter(d => getClientLayer(d.client_type ?? '') === 'EL'); + + const clRead = clData.filter(d => d.rw === 'read'); + const clWrite = clData.filter(d => d.rw === 'write'); + const elRead = elData.filter(d => d.rw === 'read'); + const elWrite = elData.filter(d => d.rw === 'write'); chartSeries.push({ - name: 'Read', - data: toPoints(bucketData(readData)), + name: 'CL Read', + data: toPoints(bucketData(clRead)), color: CHART_CATEGORICAL_COLORS[0], lineWidth: 2, showArea: true, @@ -155,14 +160,32 @@ export function DiskIoChart({ smooth: 0.4, }); chartSeries.push({ - name: 'Write', - data: toPoints(bucketData(writeData)), + name: 'CL Write', + data: toPoints(bucketData(clWrite)), + color: CHART_CATEGORICAL_COLORS[0], + lineWidth: 1.5, + lineStyle: 'dashed', + showArea: false, + smooth: 0.4, + }); + chartSeries.push({ + name: 'EL Read', + data: toPoints(bucketData(elRead)), color: CHART_CATEGORICAL_COLORS[1], lineWidth: 2, showArea: true, areaOpacity: 0.08, smooth: 0.4, }); + chartSeries.push({ + name: 'EL Write', + data: toPoints(bucketData(elWrite)), + color: CHART_CATEGORICAL_COLORS[1], + lineWidth: 1.5, + lineStyle: 'dashed', + showArea: false, + smooth: 0.4, + }); } return { series: chartSeries, clClient: resolvedClClient, elClient: resolvedElClient }; From 1f78c323a77223a36d45591cc2d7b19a0ab10025 Mon Sep 17 00:00:00 2001 From: Sam Calder-Mason Date: Thu, 12 Feb 2026 22:00:02 +1000 Subject: [PATCH 12/15] Plot data points at end of aggregation window Shift bucket offset by BUCKET_SIZE (250ms) so each data point represents the end of its aggregation window rather than the start. --- .../slots/components/NodeResources/CpuUtilizationChart.tsx | 2 +- .../ethereum/slots/components/NodeResources/DiskIoChart.tsx | 2 +- .../slots/components/NodeResources/MemoryUsageChart.tsx | 2 +- .../ethereum/slots/components/NodeResources/NetworkIoChart.tsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx b/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx index a76d14333..39925f4eb 100644 --- a/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx @@ -104,7 +104,7 @@ export function CpuUtilizationChart({ const bucketData = (items: FctNodeCpuUtilizationByProcess[]): Map => { const buckets = new Map(); for (const d of items) { - const offset = usToSeconds((d.window_start ?? 0) - slotStartUs); + const offset = usToSeconds((d.window_start ?? 0) - slotStartUs) + BUCKET_SIZE; const bucket = toBucket(offset); if (bucket < 0 || bucket > 12) continue; diff --git a/src/pages/ethereum/slots/components/NodeResources/DiskIoChart.tsx b/src/pages/ethereum/slots/components/NodeResources/DiskIoChart.tsx index 88b5d3921..e6d6e4614 100644 --- a/src/pages/ethereum/slots/components/NodeResources/DiskIoChart.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/DiskIoChart.tsx @@ -76,7 +76,7 @@ export function DiskIoChart({ const bucketData = (items: FctNodeDiskIoByProcess[]): Map => { const buckets = new Map(); for (const d of items) { - const offset = usToSeconds((d.window_start ?? 0) - slotStartUs); + const offset = usToSeconds((d.window_start ?? 0) - slotStartUs) + BUCKET_SIZE; const bucket = toBucket(offset); if (bucket < 0 || bucket > 12) continue; diff --git a/src/pages/ethereum/slots/components/NodeResources/MemoryUsageChart.tsx b/src/pages/ethereum/slots/components/NodeResources/MemoryUsageChart.tsx index d51de2355..96ddbd0cd 100644 --- a/src/pages/ethereum/slots/components/NodeResources/MemoryUsageChart.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/MemoryUsageChart.tsx @@ -110,7 +110,7 @@ export function MemoryUsageChart({ const bucketData = (items: FctNodeMemoryUsageByProcess[]): Map => { const buckets = new Map(); for (const d of items) { - const offset = usToSeconds((d.window_start ?? 0) - slotStartUs); + const offset = usToSeconds((d.window_start ?? 0) - slotStartUs) + BUCKET_SIZE; const bucket = toBucket(offset); if (bucket < 0 || bucket > 12) continue; diff --git a/src/pages/ethereum/slots/components/NodeResources/NetworkIoChart.tsx b/src/pages/ethereum/slots/components/NodeResources/NetworkIoChart.tsx index 992b4d012..a40e93604 100644 --- a/src/pages/ethereum/slots/components/NodeResources/NetworkIoChart.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/NetworkIoChart.tsx @@ -96,7 +96,7 @@ export function NetworkIoChart({ // Bucket and aggregate tx+rx bytes const buckets = new Map(); for (const d of filteredPortData) { - const offset = usToSeconds((d.window_start ?? 0) - slotStartUs); + const offset = usToSeconds((d.window_start ?? 0) - slotStartUs) + BUCKET_SIZE; const bucket = toBucket(offset); if (bucket < 0 || bucket > 12) continue; From f2e5b40ecf0a5a05ac11e747f4daf2ebe30dcea3 Mon Sep 17 00:00:00 2001 From: Sam Calder-Mason Date: Thu, 12 Feb 2026 22:07:38 +1000 Subject: [PATCH 13/15] Forward-fill gauge metrics (CPU, memory) instead of zero-filling Gauge metrics always have a value, so empty leading buckets should use the first known value rather than 0. Prevents false spike from 0 at chart start. Delta metrics (disk, network) still zero-fill correctly. --- .../NodeResources/CpuUtilizationChart.tsx | 18 ++++++++++++++++-- .../NodeResources/MemoryUsageChart.tsx | 18 ++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx b/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx index 39925f4eb..79c942d1c 100644 --- a/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx @@ -121,8 +121,22 @@ export function CpuUtilizationChart({ return buckets; }; - const toPoints = (buckets: Map, extract: (b: BucketAgg) => number[]): [number, number][] => - ALL_BUCKETS.map(t => [t, buckets.has(t) ? avg(extract(buckets.get(t)!)) : 0] as [number, number]); + const toPoints = (buckets: Map, extract: (b: BucketAgg) => number[]): [number, number][] => { + const points: [number, number][] = ALL_BUCKETS.map( + t => [t, buckets.has(t) ? avg(extract(buckets.get(t)!)) : NaN] as [number, number] + ); + // Gauge metric: forward-fill gaps, backward-fill leading empties + const firstKnown = points.find(p => !isNaN(p[1]))?.[1] ?? 0; + let last = firstKnown; + for (const p of points) { + if (isNaN(p[1])) { + p[1] = last; + } else { + last = p[1]; + } + } + return points; + }; const metricExtract = (b: BucketAgg): number[] => { switch (metric) { diff --git a/src/pages/ethereum/slots/components/NodeResources/MemoryUsageChart.tsx b/src/pages/ethereum/slots/components/NodeResources/MemoryUsageChart.tsx index 96ddbd0cd..a68e88147 100644 --- a/src/pages/ethereum/slots/components/NodeResources/MemoryUsageChart.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/MemoryUsageChart.tsx @@ -120,8 +120,22 @@ export function MemoryUsageChart({ return buckets; }; - const toPoints = (buckets: Map): [number, number][] => - ALL_BUCKETS.map(t => [t, buckets.has(t) ? avg(buckets.get(t)!) : 0] as [number, number]); + const toPoints = (buckets: Map): [number, number][] => { + const points: [number, number][] = ALL_BUCKETS.map( + t => [t, buckets.has(t) ? avg(buckets.get(t)!) : NaN] as [number, number] + ); + // Gauge metric: forward-fill gaps, backward-fill leading empties + const firstKnown = points.find(p => !isNaN(p[1]))?.[1] ?? 0; + let last = firstKnown; + for (const p of points) { + if (isNaN(p[1])) { + p[1] = last; + } else { + last = p[1]; + } + } + return points; + }; if (selectedNode) { const nodeData = data.filter(d => d.meta_client_name === selectedNode); From f98bb867d4765277d229e806f2df708712bffa6d Mon Sep 17 00:00:00 2001 From: Sam Calder-Mason Date: Fri, 13 Feb 2026 09:59:55 +1000 Subject: [PATCH 14/15] fixes --- src/components/Charts/MultiLine/MultiLine.tsx | 4 +- .../Charts/MultiLine/MultiLine.types.ts | 5 + .../NodeResources/AnnotationSwimLanes.tsx | 183 ++++++++++++ .../NodeResources/CpuUtilizationChart.tsx | 264 ++++++++---------- .../components/NodeResources/DiskIoChart.tsx | 235 +++++++--------- .../NodeResources/MemoryUsageChart.tsx | 250 ++++++++--------- .../NodeResources/NetworkIoChart.tsx | 235 +++++++--------- .../NodeResources/NodeResourcesPanel.tsx | 10 + .../slots/components/NodeResources/types.ts | 6 + 9 files changed, 640 insertions(+), 552 deletions(-) create mode 100644 src/pages/ethereum/slots/components/NodeResources/AnnotationSwimLanes.tsx diff --git a/src/components/Charts/MultiLine/MultiLine.tsx b/src/components/Charts/MultiLine/MultiLine.tsx index 88f60025f..9e379aa4c 100644 --- a/src/components/Charts/MultiLine/MultiLine.tsx +++ b/src/components/Charts/MultiLine/MultiLine.tsx @@ -98,6 +98,7 @@ export function MultiLineChart({ onSeriesClick, markLines, markAreas, + onChartReady: onChartReadyProp, }: MultiLineChartProps): React.JSX.Element { // Store ref to the ReactEChartsCore wrapper (not the instance) for click handling const chartWrapperRef = useRef(null); @@ -118,6 +119,7 @@ export function MultiLineChart({ if (syncGroup && crosshairsContext) { crosshairsContext.registerChart(syncGroup, echartsInstance); } + onChartReadyProp?.(echartsInstance); // Track dataZoom changes to preserve zoom state across data updates and legend toggles // Using state ensures the zoom range is included in the option config on re-renders @@ -142,7 +144,7 @@ export function MultiLineChart({ echartsInstance.on('datazoom', handleDataZoom); } }, - [syncGroup, crosshairsContext, enableDataZoom] + [syncGroup, crosshairsContext, enableDataZoom, onChartReadyProp] ); // Cleanup sync registration on unmount or syncGroup change diff --git a/src/components/Charts/MultiLine/MultiLine.types.ts b/src/components/Charts/MultiLine/MultiLine.types.ts index de14ab980..d1d074747 100644 --- a/src/components/Charts/MultiLine/MultiLine.types.ts +++ b/src/components/Charts/MultiLine/MultiLine.types.ts @@ -443,4 +443,9 @@ export interface MultiLineChartProps { * Renders semi-transparent colored rectangles spanning the full y-axis */ markAreas?: MarkAreaConfig[]; + /** + * Callback fired when the chart instance is ready + * Provides access to the underlying ECharts instance for advanced use cases + */ + onChartReady?: (instance: import('echarts-for-react/lib').EChartsInstance) => void; } diff --git a/src/pages/ethereum/slots/components/NodeResources/AnnotationSwimLanes.tsx b/src/pages/ethereum/slots/components/NodeResources/AnnotationSwimLanes.tsx new file mode 100644 index 000000000..662115d82 --- /dev/null +++ b/src/pages/ethereum/slots/components/NodeResources/AnnotationSwimLanes.tsx @@ -0,0 +1,183 @@ +import { type JSX, useMemo } from 'react'; +import { ANNOTATION_COLORS, ANNOTATION_OPTIONS, type AnnotationType, type AnnotationEvent, type HighlightRange } from './types'; + +/** Minimum visual width (fraction of 0–1) so point events remain clickable/visible */ +const MIN_MARK_FRAC = 0.08 / 12; + +/** Annotation types rendered as swim lanes (slot_phases excluded – those stay as chart markLines) */ +const LANE_TYPES: Exclude[] = ['block', 'head', 'execution', 'data_columns']; + +const LANE_LABELS: Record = Object.fromEntries( + ANNOTATION_OPTIONS.filter(o => o.value !== 'slot_phases').map(o => [o.value, o.label]) +); + +function nodeMatches(nodeName: string, selectedNode: string): boolean { + const short = nodeName.split('/').pop() ?? nodeName; + return ( + selectedNode === short || selectedNode === nodeName || short.includes(selectedNode) || selectedNode.includes(short) + ); +} + +function percentile(sorted: number[], p: number): number { + const idx = Math.floor(sorted.length * p); + return sorted[Math.min(idx, sorted.length - 1)]; +} + +interface AnnotationSwimLanesProps { + annotations: AnnotationEvent[]; + enabledAnnotations: Set; + selectedNode: string | null; + /** Left offset of the chart grid in pixels (matches y-axis label area) */ + gridLeft: number; + /** Right offset of the chart grid in pixels */ + gridRight: number; + /** Called when a swim lane mark is hovered/unhovered */ + onHighlight?: (range: HighlightRange | null) => void; +} + +interface LaneMark { + leftPct: number; + widthPct: number; + color: string; + opacity: number; +} + +export function AnnotationSwimLanes({ + annotations, + enabledAnnotations, + selectedNode, + gridLeft, + gridRight, + onHighlight, +}: AnnotationSwimLanesProps): JSX.Element | null { + const lanes = useMemo(() => { + const result: { type: string; label: string; marks: LaneMark[] }[] = []; + + for (const laneType of LANE_TYPES) { + if (!enabledAnnotations.has(laneType)) continue; + + const color = ANNOTATION_COLORS[laneType]; + const marks: LaneMark[] = []; + + if (selectedNode) { + // Single node: exact event positions + for (const anno of annotations) { + if (anno.type !== laneType) continue; + if (!anno.nodeName || !nodeMatches(anno.nodeName, selectedNode)) continue; + + const startFrac = anno.timeMs / 12000; + if (startFrac < 0 || startFrac > 1) continue; + + const hasRange = anno.endMs != null && Math.abs(anno.endMs - anno.timeMs) > 10; + + if (hasRange) { + const endFrac = Math.min(anno.endMs! / 12000, 1); + marks.push({ + leftPct: startFrac * 100, + widthPct: Math.max((endFrac - startFrac) * 100, MIN_MARK_FRAC * 100), + color, + opacity: 0.6, + }); + } else { + marks.push({ + leftPct: Math.max(0, startFrac - MIN_MARK_FRAC / 2) * 100, + widthPct: MIN_MARK_FRAC * 100, + color, + opacity: 0.8, + }); + } + } + } else { + // Aggregate: min–p95 spread + const events = annotations.filter(a => a.type === laneType); + if (events.length === 0) continue; + + const hasRanges = events.some(e => e.endMs != null); + + if (hasRanges) { + const starts = events.map(e => e.timeMs).sort((a, b) => a - b); + const ends = events.map(e => e.endMs ?? e.timeMs).sort((a, b) => a - b); + const startFrac = starts[0] / 12000; + const endFrac = Math.min(percentile(ends, 0.95) / 12000, 1); + if (startFrac >= 0 && startFrac <= 1) { + marks.push({ + leftPct: Math.max(0, startFrac) * 100, + widthPct: Math.max((endFrac - startFrac) * 100, MIN_MARK_FRAC * 100), + color, + opacity: 0.5, + }); + } + } else { + const times = events.map(e => e.timeMs).sort((a, b) => a - b); + const minFrac = times[0] / 12000; + const p95Frac = percentile(times, 0.95) / 12000; + if (minFrac >= 0 && p95Frac <= 1) { + const width = p95Frac - minFrac; + if (width < MIN_MARK_FRAC) { + const medFrac = percentile(times, 0.5) / 12000; + marks.push({ + leftPct: Math.max(0, medFrac - MIN_MARK_FRAC / 2) * 100, + widthPct: MIN_MARK_FRAC * 100, + color, + opacity: 0.7, + }); + } else { + marks.push({ + leftPct: minFrac * 100, + widthPct: (p95Frac - minFrac) * 100, + color, + opacity: 0.5, + }); + } + } + } + } + + if (marks.length > 0) { + result.push({ type: laneType, label: LANE_LABELS[laneType] ?? laneType, marks }); + } + } + + return result; + }, [annotations, enabledAnnotations, selectedNode]); + + if (lanes.length === 0) return null; + + return ( +
+ {lanes.map(lane => ( +
+ + {lane.label} + +
+ {lane.marks.map((mark, i) => ( +
+ onHighlight?.({ + startFrac: mark.leftPct / 100, + widthFrac: mark.widthPct / 100, + color: mark.color, + }) + } + onMouseLeave={() => onHighlight?.(null)} + /> + ))} +
+
+ ))} +
+ ); +} diff --git a/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx b/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx index 79c942d1c..eb5e33aa4 100644 --- a/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx @@ -1,13 +1,14 @@ -import { type JSX, useMemo } from 'react'; +import { type JSX, useCallback, useMemo, useState } from 'react'; import { PopoutCard } from '@/components/Layout/PopoutCard'; import { MultiLineChart } from '@/components/Charts/MultiLine'; -import type { SeriesData, MarkAreaConfig, MarkLineConfig } from '@/components/Charts/MultiLine/MultiLine.types'; +import type { SeriesData, MarkLineConfig } from '@/components/Charts/MultiLine/MultiLine.types'; import { getDataVizColors, getClientLayer } from '@/utils'; import { DEFAULT_BEACON_SLOT_PHASES } from '@/utils/beacon'; import { ClientLogo } from '@/components/Ethereum/ClientLogo'; import { SelectMenu } from '@/components/Forms/SelectMenu'; import type { FctNodeCpuUtilizationByProcess } from '@/api/types.gen'; -import { ANNOTATION_COLORS, type CpuMetric, type AnnotationType, type AnnotationEvent } from './types'; +import { type CpuMetric, type AnnotationType, type AnnotationEvent, type HighlightRange } from './types'; +import { AnnotationSwimLanes } from './AnnotationSwimLanes'; function usToSeconds(us: number): number { return us / 1_000_000; @@ -34,20 +35,6 @@ const METRIC_OPTIONS = [ { value: 'max' as CpuMetric, label: 'Max' }, ]; -/** Minimum width in seconds for point-event areas so they're visible */ -const MIN_AREA_WIDTH_SEC = 0.08; - -/** Match a CPU node name to propagation node_id (fuzzy matching) */ -function nodeMatches(cpuNodeName: string, propNodeId: string): boolean { - const short = cpuNodeName.split('/').pop() ?? cpuNodeName; - return propNodeId === short || propNodeId === cpuNodeName || short.includes(propNodeId) || propNodeId.includes(short); -} - -function percentile(sorted: number[], p: number): number { - const idx = Math.floor(sorted.length * p); - return sorted[Math.min(idx, sorted.length - 1)]; -} - interface BucketAgg { meanVals: number[]; minVals: number[]; @@ -63,6 +50,8 @@ interface CpuUtilizationChartProps { slot: number; annotations: AnnotationEvent[]; enabledAnnotations: Set; + highlight: HighlightRange | null; + onHighlight: (range: HighlightRange | null) => void; } /** Slot phase boundary colors: cyan (block), green (attestation), amber (aggregation) */ @@ -88,9 +77,32 @@ export function CpuUtilizationChart({ slot, annotations, enabledAnnotations, + highlight, + onHighlight, }: CpuUtilizationChartProps): JSX.Element { const { CHART_CATEGORICAL_COLORS } = getDataVizColors(); + const [gridOffsets, setGridOffsets] = useState({ left: 60, right: 24, height: 350 }); + const handleChartReady = useCallback( + (instance: { + convertToPixel: (finder: { gridIndex: number }, value: number[]) => number[]; + getDom: () => HTMLElement | null; + }) => { + try { + const px0 = instance.convertToPixel({ gridIndex: 0 }, [0, 0]); + const px12 = instance.convertToPixel({ gridIndex: 0 }, [12, 0]); + const width = instance.getDom()?.clientWidth ?? 0; + if (px0 && px12 && width > 0) { + // px0[1] = pixel Y of the x-axis from the top of the ECharts DOM + setGridOffsets({ left: Math.round(px0[0]), right: Math.round(width - px12[0]), height: Math.round(px0[1]) }); + } + } catch { + /* use defaults */ + } + }, + [] + ); + const { series, clClient, elClient } = useMemo(() => { if (data.length === 0) { return { series: [] as SeriesData[], clClient: '', elClient: '' }; @@ -237,87 +249,6 @@ export function CpuUtilizationChart({ return { series: chartSeries, clClient: resolvedClClient, elClient: resolvedElClient }; }, [data, selectedNode, metric, CHART_CATEGORICAL_COLORS]); - // Convert annotations to markAreas (chart handles node matching + aggregation) - const markAreas = useMemo((): MarkAreaConfig[] => { - const areas: MarkAreaConfig[] = []; - - if (selectedNode) { - // Single node: find matching events and render exact positions - for (const anno of annotations) { - if (!enabledAnnotations.has(anno.type)) continue; - if (!anno.nodeName || !nodeMatches(selectedNode, anno.nodeName)) continue; - - const startSec = anno.timeMs / 1000; - if (startSec < 0 || startSec > 12) continue; - const color = ANNOTATION_COLORS[anno.type]; - const hasRange = anno.endMs != null && Math.abs(anno.endMs - anno.timeMs) > 10; - - if (hasRange) { - const endSec = Math.min(anno.endMs! / 1000, 12); - areas.push({ xStart: startSec, xEnd: endSec, color, opacity: 0.12 }); - } else { - areas.push({ - xStart: startSec - MIN_AREA_WIDTH_SEC / 2, - xEnd: startSec + MIN_AREA_WIDTH_SEC / 2, - color, - opacity: 0.3, - }); - } - } - } else { - // Aggregate: compute min–p95 range per annotation type - const byType = new Map(); - for (const anno of annotations) { - if (!enabledAnnotations.has(anno.type)) continue; - if (!byType.has(anno.type)) byType.set(anno.type, []); - byType.get(anno.type)!.push(anno); - } - - for (const [type, events] of byType) { - const color = ANNOTATION_COLORS[type]; - const hasRanges = events.some(e => e.endMs != null); - - if (hasRanges) { - // Range events (execution, data_columns): min of starts → p95 of ends - const starts = events.map(e => e.timeMs).sort((a, b) => a - b); - const ends = events.map(e => e.endMs ?? e.timeMs).sort((a, b) => a - b); - const startSec = starts[0] / 1000; - const endSec = percentile(ends, 0.95) / 1000; - if (startSec >= 0 && startSec <= 12) { - areas.push({ - xStart: Math.max(0, startSec), - xEnd: Math.min(12, endSec), - color, - opacity: 0.1, - }); - } - } else { - // Point events (block, head): min–p95 spread as area - const times = events.map(e => e.timeMs).sort((a, b) => a - b); - const minSec = times[0] / 1000; - const p95Sec = percentile(times, 0.95) / 1000; - if (minSec >= 0 && p95Sec <= 12) { - const width = p95Sec - minSec; - if (width < MIN_AREA_WIDTH_SEC) { - // Very tight spread: render as thin band at median - const medSec = percentile(times, 0.5) / 1000; - areas.push({ - xStart: medSec - MIN_AREA_WIDTH_SEC / 2, - xEnd: medSec + MIN_AREA_WIDTH_SEC / 2, - color, - opacity: 0.25, - }); - } else { - areas.push({ xStart: minSec, xEnd: p95Sec, color, opacity: 0.1 }); - } - } - } - } - } - - return areas; - }, [annotations, enabledAnnotations, selectedNode]); - const markLines = useMemo((): MarkLineConfig[] => { if (!enabledAnnotations.has('slot_phases')) return []; @@ -350,15 +281,12 @@ export function CpuUtilizationChart({ ? `Slot ${slot} · ${shortNodeName} · % of all CPU cores` : `Slot ${slot} · ${METRIC_LABELS[metric]} across ${nodeCount} nodes · % of all CPU cores`; - const headerActions = selectedNode ? ( - clClient || elClient ? ( -
- {clClient && } - {elClient && } -
- ) : undefined - ) : ( - + const headerActions = ( +
+ {selectedNode && clClient && } + {selectedNode && elClient && } + +
); if (data.length === 0) { @@ -378,51 +306,83 @@ export function CpuUtilizationChart({ return ( {({ inModal }) => ( - `${v}s`, - }} - yAxis={{ - name: '% of all cores', - min: 0, - formatter: (v: number) => `${v.toFixed(1)}%`, - }} - height={inModal ? 500 : 350} - showLegend - legendPosition="bottom" - markLines={markLines} - markAreas={markAreas} - syncGroup="slot-time" - tooltipFormatter={(params: unknown) => { - const items = (Array.isArray(params) ? params : [params]) as EChartsTooltipParam[]; - if (items.length === 0) return ''; - - const first = items[0]; - const xVal = Array.isArray(first.value) ? first.value[0] : first.axisValue; - const timeStr = typeof xVal === 'number' ? `${xVal.toFixed(2)}s` : `${xVal}s`; - - let html = `
`; - html += `
${timeStr}
`; - - for (const p of items) { - const val = Array.isArray(p.value) ? p.value[1] : p.value; - if (val == null) continue; - html += `
`; - html += `${p.marker}`; - html += `${p.seriesName}`; - html += `${Number(val).toFixed(1)}%`; - html += `
`; - } - - html += `
`; - return html; - }} - /> + <> +
+ `${v}s`, + }} + yAxis={{ + name: '% of all cores', + min: 0, + formatter: (v: number) => `${v.toFixed(1)}%`, + }} + height={inModal ? 500 : 350} + showLegend + legendPosition="bottom" + markLines={markLines} + syncGroup="slot-time" + onChartReady={handleChartReady} + tooltipFormatter={(params: unknown) => { + const items = (Array.isArray(params) ? params : [params]) as EChartsTooltipParam[]; + if (items.length === 0) return ''; + + const first = items[0]; + const xVal = Array.isArray(first.value) ? first.value[0] : first.axisValue; + const timeStr = typeof xVal === 'number' ? `${xVal.toFixed(2)}s` : `${xVal}s`; + + let html = `
`; + html += `
${timeStr}
`; + + for (const p of items) { + const val = Array.isArray(p.value) ? p.value[1] : p.value; + if (val == null) continue; + html += `
`; + html += `${p.marker}`; + html += `${p.seriesName}`; + html += `${Number(val).toFixed(1)}%`; + html += `
`; + } + + html += `
`; + return html; + }} + /> + {highlight && ( +
+
+
+ )} +
+ + )} ); diff --git a/src/pages/ethereum/slots/components/NodeResources/DiskIoChart.tsx b/src/pages/ethereum/slots/components/NodeResources/DiskIoChart.tsx index e6d6e4614..8352ad55d 100644 --- a/src/pages/ethereum/slots/components/NodeResources/DiskIoChart.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/DiskIoChart.tsx @@ -1,12 +1,13 @@ -import { type JSX, useMemo } from 'react'; +import { type JSX, useCallback, useMemo, useState } from 'react'; import { PopoutCard } from '@/components/Layout/PopoutCard'; import { MultiLineChart } from '@/components/Charts/MultiLine'; -import type { SeriesData, MarkAreaConfig, MarkLineConfig } from '@/components/Charts/MultiLine/MultiLine.types'; +import type { SeriesData, MarkLineConfig } from '@/components/Charts/MultiLine/MultiLine.types'; import { getDataVizColors, getClientLayer } from '@/utils'; import { DEFAULT_BEACON_SLOT_PHASES } from '@/utils/beacon'; import { ClientLogo } from '@/components/Ethereum/ClientLogo'; import type { FctNodeDiskIoByProcess } from '@/api/types.gen'; -import { ANNOTATION_COLORS, type AnnotationType, type AnnotationEvent } from './types'; +import { type AnnotationType, type AnnotationEvent, type HighlightRange } from './types'; +import { AnnotationSwimLanes } from './AnnotationSwimLanes'; function usToSeconds(us: number): number { return us / 1_000_000; @@ -20,18 +21,6 @@ function bytesToKB(bytes: number): number { return bytes / 1024; } -const MIN_AREA_WIDTH_SEC = 0.08; - -function nodeMatches(cpuNodeName: string, propNodeId: string): boolean { - const short = cpuNodeName.split('/').pop() ?? cpuNodeName; - return propNodeId === short || propNodeId === cpuNodeName || short.includes(propNodeId) || propNodeId.includes(short); -} - -function percentile(sorted: number[], p: number): number { - const idx = Math.floor(sorted.length * p); - return sorted[Math.min(idx, sorted.length - 1)]; -} - const BUCKET_SIZE = 0.25; const ALL_BUCKETS = Array.from({ length: 49 }, (_, i) => i * BUCKET_SIZE); const toBucket = (offsetSec: number): number => Math.round(offsetSec / BUCKET_SIZE) * BUCKET_SIZE; @@ -43,6 +32,8 @@ interface DiskIoChartProps { slot: number; annotations: AnnotationEvent[]; enabledAnnotations: Set; + highlight: HighlightRange | null; + onHighlight: (range: HighlightRange | null) => void; } const PHASE_BOUNDARY_COLORS = ['#22d3ee', '#22c55e', '#f59e0b']; @@ -60,9 +51,31 @@ export function DiskIoChart({ slot, annotations, enabledAnnotations, + highlight, + onHighlight, }: DiskIoChartProps): JSX.Element { const { CHART_CATEGORICAL_COLORS } = getDataVizColors(); + const [gridOffsets, setGridOffsets] = useState({ left: 60, right: 24, height: 350 }); + const handleChartReady = useCallback( + (instance: { + convertToPixel: (finder: { gridIndex: number }, value: number[]) => number[]; + getDom: () => HTMLElement | null; + }) => { + try { + const px0 = instance.convertToPixel({ gridIndex: 0 }, [0, 0]); + const px12 = instance.convertToPixel({ gridIndex: 0 }, [12, 0]); + const width = instance.getDom()?.clientWidth ?? 0; + if (px0 && px12 && width > 0) { + setGridOffsets({ left: Math.round(px0[0]), right: Math.round(width - px12[0]), height: Math.round(px0[1]) }); + } + } catch { + /* use defaults */ + } + }, + [] + ); + const { series, clClient, elClient } = useMemo(() => { if (data.length === 0) { return { series: [] as SeriesData[], clClient: '', elClient: '' }; @@ -191,76 +204,6 @@ export function DiskIoChart({ return { series: chartSeries, clClient: resolvedClClient, elClient: resolvedElClient }; }, [data, selectedNode, CHART_CATEGORICAL_COLORS]); - const markAreas = useMemo((): MarkAreaConfig[] => { - const areas: MarkAreaConfig[] = []; - - if (selectedNode) { - for (const anno of annotations) { - if (!enabledAnnotations.has(anno.type)) continue; - if (!anno.nodeName || !nodeMatches(selectedNode, anno.nodeName)) continue; - - const startSec = anno.timeMs / 1000; - if (startSec < 0 || startSec > 12) continue; - const color = ANNOTATION_COLORS[anno.type]; - const hasRange = anno.endMs != null && Math.abs(anno.endMs - anno.timeMs) > 10; - - if (hasRange) { - const endSec = Math.min(anno.endMs! / 1000, 12); - areas.push({ xStart: startSec, xEnd: endSec, color, opacity: 0.12 }); - } else { - areas.push({ - xStart: startSec - MIN_AREA_WIDTH_SEC / 2, - xEnd: startSec + MIN_AREA_WIDTH_SEC / 2, - color, - opacity: 0.3, - }); - } - } - } else { - const byType = new Map(); - for (const anno of annotations) { - if (!enabledAnnotations.has(anno.type)) continue; - if (!byType.has(anno.type)) byType.set(anno.type, []); - byType.get(anno.type)!.push(anno); - } - - for (const [type, events] of byType) { - const color = ANNOTATION_COLORS[type]; - const hasRanges = events.some(e => e.endMs != null); - - if (hasRanges) { - const starts = events.map(e => e.timeMs).sort((a, b) => a - b); - const ends = events.map(e => e.endMs ?? e.timeMs).sort((a, b) => a - b); - const startSec = starts[0] / 1000; - const endSec = percentile(ends, 0.95) / 1000; - if (startSec >= 0 && startSec <= 12) { - areas.push({ xStart: Math.max(0, startSec), xEnd: Math.min(12, endSec), color, opacity: 0.1 }); - } - } else { - const times = events.map(e => e.timeMs).sort((a, b) => a - b); - const minSec = times[0] / 1000; - const p95Sec = percentile(times, 0.95) / 1000; - if (minSec >= 0 && p95Sec <= 12) { - const width = p95Sec - minSec; - if (width < MIN_AREA_WIDTH_SEC) { - const medSec = percentile(times, 0.5) / 1000; - areas.push({ - xStart: medSec - MIN_AREA_WIDTH_SEC / 2, - xEnd: medSec + MIN_AREA_WIDTH_SEC / 2, - color, - opacity: 0.25, - }); - } else { - areas.push({ xStart: minSec, xEnd: p95Sec, color, opacity: 0.1 }); - } - } - } - } - } - - return areas; - }, [annotations, enabledAnnotations, selectedNode]); - const markLines = useMemo((): MarkLineConfig[] => { if (!enabledAnnotations.has('slot_phases')) return []; @@ -318,51 +261,83 @@ export function DiskIoChart({ return ( {({ inModal }) => ( - `${v}s`, - }} - yAxis={{ - name: 'KB', - min: 0, - formatter: (v: number) => `${v.toFixed(0)} KB`, - }} - height={inModal ? 500 : 350} - showLegend - legendPosition="bottom" - markLines={markLines} - markAreas={markAreas} - syncGroup="slot-time" - tooltipFormatter={(params: unknown) => { - const items = (Array.isArray(params) ? params : [params]) as EChartsTooltipParam[]; - if (items.length === 0) return ''; - - const first = items[0]; - const xVal = Array.isArray(first.value) ? first.value[0] : first.axisValue; - const timeStr = typeof xVal === 'number' ? `${xVal.toFixed(2)}s` : `${xVal}s`; - - let html = `
`; - html += `
${timeStr}
`; - - for (const p of items) { - const val = Array.isArray(p.value) ? p.value[1] : p.value; - if (val == null) continue; - html += `
`; - html += `${p.marker}`; - html += `${p.seriesName}`; - html += `${Number(val).toFixed(1)} KB`; - html += `
`; - } - - html += `
`; - return html; - }} - /> + <> +
+ `${v}s`, + }} + yAxis={{ + name: 'KB', + min: 0, + formatter: (v: number) => `${v.toFixed(0)} KB`, + }} + height={inModal ? 500 : 350} + showLegend + legendPosition="bottom" + markLines={markLines} + syncGroup="slot-time" + onChartReady={handleChartReady} + tooltipFormatter={(params: unknown) => { + const items = (Array.isArray(params) ? params : [params]) as EChartsTooltipParam[]; + if (items.length === 0) return ''; + + const first = items[0]; + const xVal = Array.isArray(first.value) ? first.value[0] : first.axisValue; + const timeStr = typeof xVal === 'number' ? `${xVal.toFixed(2)}s` : `${xVal}s`; + + let html = `
`; + html += `
${timeStr}
`; + + for (const p of items) { + const val = Array.isArray(p.value) ? p.value[1] : p.value; + if (val == null) continue; + html += `
`; + html += `${p.marker}`; + html += `${p.seriesName}`; + html += `${Number(val).toFixed(1)} KB`; + html += `
`; + } + + html += `
`; + return html; + }} + /> + {highlight && ( +
+
+
+ )} +
+ + )} ); diff --git a/src/pages/ethereum/slots/components/NodeResources/MemoryUsageChart.tsx b/src/pages/ethereum/slots/components/NodeResources/MemoryUsageChart.tsx index a68e88147..4f01586f6 100644 --- a/src/pages/ethereum/slots/components/NodeResources/MemoryUsageChart.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/MemoryUsageChart.tsx @@ -1,13 +1,14 @@ -import { type JSX, useMemo } from 'react'; +import { type JSX, useCallback, useMemo, useState } from 'react'; import { PopoutCard } from '@/components/Layout/PopoutCard'; import { MultiLineChart } from '@/components/Charts/MultiLine'; -import type { SeriesData, MarkAreaConfig, MarkLineConfig } from '@/components/Charts/MultiLine/MultiLine.types'; +import type { SeriesData, MarkLineConfig } from '@/components/Charts/MultiLine/MultiLine.types'; import { getDataVizColors, getClientLayer } from '@/utils'; import { DEFAULT_BEACON_SLOT_PHASES } from '@/utils/beacon'; import { ClientLogo } from '@/components/Ethereum/ClientLogo'; import { SelectMenu } from '@/components/Forms/SelectMenu'; import type { FctNodeMemoryUsageByProcess } from '@/api/types.gen'; -import { ANNOTATION_COLORS, type AnnotationType, type AnnotationEvent } from './types'; +import { type AnnotationType, type AnnotationEvent, type HighlightRange } from './types'; +import { AnnotationSwimLanes } from './AnnotationSwimLanes'; function usToSeconds(us: number): number { return us / 1_000_000; @@ -37,18 +38,6 @@ const METRIC_OPTIONS = [ { value: 'vm_swap' as MemoryMetric, label: 'Swap' }, ]; -const MIN_AREA_WIDTH_SEC = 0.08; - -function nodeMatches(cpuNodeName: string, propNodeId: string): boolean { - const short = cpuNodeName.split('/').pop() ?? cpuNodeName; - return propNodeId === short || propNodeId === cpuNodeName || short.includes(propNodeId) || propNodeId.includes(short); -} - -function percentile(sorted: number[], p: number): number { - const idx = Math.floor(sorted.length * p); - return sorted[Math.min(idx, sorted.length - 1)]; -} - const BUCKET_SIZE = 0.25; const ALL_BUCKETS = Array.from({ length: 49 }, (_, i) => i * BUCKET_SIZE); const toBucket = (offsetSec: number): number => Math.round(offsetSec / BUCKET_SIZE) * BUCKET_SIZE; @@ -75,6 +64,8 @@ interface MemoryUsageChartProps { slot: number; annotations: AnnotationEvent[]; enabledAnnotations: Set; + highlight: HighlightRange | null; + onHighlight: (range: HighlightRange | null) => void; } const PHASE_BOUNDARY_COLORS = ['#22d3ee', '#22c55e', '#f59e0b']; @@ -94,9 +85,31 @@ export function MemoryUsageChart({ slot, annotations, enabledAnnotations, + highlight, + onHighlight, }: MemoryUsageChartProps): JSX.Element { const { CHART_CATEGORICAL_COLORS } = getDataVizColors(); + const [gridOffsets, setGridOffsets] = useState({ left: 60, right: 24, height: 350 }); + const handleChartReady = useCallback( + (instance: { + convertToPixel: (finder: { gridIndex: number }, value: number[]) => number[]; + getDom: () => HTMLElement | null; + }) => { + try { + const px0 = instance.convertToPixel({ gridIndex: 0 }, [0, 0]); + const px12 = instance.convertToPixel({ gridIndex: 0 }, [12, 0]); + const width = instance.getDom()?.clientWidth ?? 0; + if (px0 && px12 && width > 0) { + setGridOffsets({ left: Math.round(px0[0]), right: Math.round(width - px12[0]), height: Math.round(px0[1]) }); + } + } catch { + /* use defaults */ + } + }, + [] + ); + const { series, clClient, elClient } = useMemo(() => { if (data.length === 0) { return { series: [] as SeriesData[], clClient: '', elClient: '' }; @@ -192,76 +205,6 @@ export function MemoryUsageChart({ return { series: chartSeries, clClient: resolvedClClient, elClient: resolvedElClient }; }, [data, selectedNode, metric, CHART_CATEGORICAL_COLORS]); - const markAreas = useMemo((): MarkAreaConfig[] => { - const areas: MarkAreaConfig[] = []; - - if (selectedNode) { - for (const anno of annotations) { - if (!enabledAnnotations.has(anno.type)) continue; - if (!anno.nodeName || !nodeMatches(selectedNode, anno.nodeName)) continue; - - const startSec = anno.timeMs / 1000; - if (startSec < 0 || startSec > 12) continue; - const color = ANNOTATION_COLORS[anno.type]; - const hasRange = anno.endMs != null && Math.abs(anno.endMs - anno.timeMs) > 10; - - if (hasRange) { - const endSec = Math.min(anno.endMs! / 1000, 12); - areas.push({ xStart: startSec, xEnd: endSec, color, opacity: 0.12 }); - } else { - areas.push({ - xStart: startSec - MIN_AREA_WIDTH_SEC / 2, - xEnd: startSec + MIN_AREA_WIDTH_SEC / 2, - color, - opacity: 0.3, - }); - } - } - } else { - const byType = new Map(); - for (const anno of annotations) { - if (!enabledAnnotations.has(anno.type)) continue; - if (!byType.has(anno.type)) byType.set(anno.type, []); - byType.get(anno.type)!.push(anno); - } - - for (const [type, events] of byType) { - const color = ANNOTATION_COLORS[type]; - const hasRanges = events.some(e => e.endMs != null); - - if (hasRanges) { - const starts = events.map(e => e.timeMs).sort((a, b) => a - b); - const ends = events.map(e => e.endMs ?? e.timeMs).sort((a, b) => a - b); - const startSec = starts[0] / 1000; - const endSec = percentile(ends, 0.95) / 1000; - if (startSec >= 0 && startSec <= 12) { - areas.push({ xStart: Math.max(0, startSec), xEnd: Math.min(12, endSec), color, opacity: 0.1 }); - } - } else { - const times = events.map(e => e.timeMs).sort((a, b) => a - b); - const minSec = times[0] / 1000; - const p95Sec = percentile(times, 0.95) / 1000; - if (minSec >= 0 && p95Sec <= 12) { - const width = p95Sec - minSec; - if (width < MIN_AREA_WIDTH_SEC) { - const medSec = percentile(times, 0.5) / 1000; - areas.push({ - xStart: medSec - MIN_AREA_WIDTH_SEC / 2, - xEnd: medSec + MIN_AREA_WIDTH_SEC / 2, - color, - opacity: 0.25, - }); - } else { - areas.push({ xStart: minSec, xEnd: p95Sec, color, opacity: 0.1 }); - } - } - } - } - } - - return areas; - }, [annotations, enabledAnnotations, selectedNode]); - const markLines = useMemo((): MarkLineConfig[] => { if (!enabledAnnotations.has('slot_phases')) return []; @@ -294,15 +237,12 @@ export function MemoryUsageChart({ ? `Slot ${slot} · ${shortNodeName} · ${METRIC_LABELS[metric]}` : `Slot ${slot} · Mean across ${nodeCount} nodes · ${METRIC_LABELS[metric]}`; - const headerActions = selectedNode ? ( - clClient || elClient ? ( -
- {clClient && } - {elClient && } -
- ) : undefined - ) : ( - + const headerActions = ( +
+ {selectedNode && clClient && } + {selectedNode && elClient && } + +
); if (data.length === 0) { @@ -322,51 +262,83 @@ export function MemoryUsageChart({ return ( {({ inModal }) => ( - `${v}s`, - }} - yAxis={{ - name: 'MB', - min: 0, - formatter: (v: number) => `${v.toFixed(0)} MB`, - }} - height={inModal ? 500 : 350} - showLegend - legendPosition="bottom" - markLines={markLines} - markAreas={markAreas} - syncGroup="slot-time" - tooltipFormatter={(params: unknown) => { - const items = (Array.isArray(params) ? params : [params]) as EChartsTooltipParam[]; - if (items.length === 0) return ''; - - const first = items[0]; - const xVal = Array.isArray(first.value) ? first.value[0] : first.axisValue; - const timeStr = typeof xVal === 'number' ? `${xVal.toFixed(2)}s` : `${xVal}s`; - - let html = `
`; - html += `
${timeStr}
`; - - for (const p of items) { - const val = Array.isArray(p.value) ? p.value[1] : p.value; - if (val == null) continue; - html += `
`; - html += `${p.marker}`; - html += `${p.seriesName}`; - html += `${Number(val).toFixed(1)} MB`; - html += `
`; - } - - html += `
`; - return html; - }} - /> + <> +
+ `${v}s`, + }} + yAxis={{ + name: 'MB', + min: 0, + formatter: (v: number) => `${v.toFixed(0)} MB`, + }} + height={inModal ? 500 : 350} + showLegend + legendPosition="bottom" + markLines={markLines} + syncGroup="slot-time" + onChartReady={handleChartReady} + tooltipFormatter={(params: unknown) => { + const items = (Array.isArray(params) ? params : [params]) as EChartsTooltipParam[]; + if (items.length === 0) return ''; + + const first = items[0]; + const xVal = Array.isArray(first.value) ? first.value[0] : first.axisValue; + const timeStr = typeof xVal === 'number' ? `${xVal.toFixed(2)}s` : `${xVal}s`; + + let html = `
`; + html += `
${timeStr}
`; + + for (const p of items) { + const val = Array.isArray(p.value) ? p.value[1] : p.value; + if (val == null) continue; + html += `
`; + html += `${p.marker}`; + html += `${p.seriesName}`; + html += `${Number(val).toFixed(1)} MB`; + html += `
`; + } + + html += `
`; + return html; + }} + /> + {highlight && ( +
+
+
+ )} +
+ + )} ); diff --git a/src/pages/ethereum/slots/components/NodeResources/NetworkIoChart.tsx b/src/pages/ethereum/slots/components/NodeResources/NetworkIoChart.tsx index a40e93604..c529abdff 100644 --- a/src/pages/ethereum/slots/components/NodeResources/NetworkIoChart.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/NetworkIoChart.tsx @@ -1,11 +1,12 @@ -import { type JSX, useMemo } from 'react'; +import { type JSX, useCallback, useMemo, useState } from 'react'; import { PopoutCard } from '@/components/Layout/PopoutCard'; import { MultiLineChart } from '@/components/Charts/MultiLine'; -import type { SeriesData, MarkAreaConfig, MarkLineConfig } from '@/components/Charts/MultiLine/MultiLine.types'; +import type { SeriesData, MarkLineConfig } from '@/components/Charts/MultiLine/MultiLine.types'; import { getDataVizColors } from '@/utils'; import { DEFAULT_BEACON_SLOT_PHASES } from '@/utils/beacon'; import type { FctNodeNetworkIoByProcess } from '@/api/types.gen'; -import { ANNOTATION_COLORS, type AnnotationType, type AnnotationEvent } from './types'; +import { type AnnotationType, type AnnotationEvent, type HighlightRange } from './types'; +import { AnnotationSwimLanes } from './AnnotationSwimLanes'; function usToSeconds(us: number): number { return us / 1_000_000; @@ -31,18 +32,6 @@ const PORT_LABELS: Record = { unknown: 'Unknown', }; -const MIN_AREA_WIDTH_SEC = 0.08; - -function nodeMatches(cpuNodeName: string, propNodeId: string): boolean { - const short = cpuNodeName.split('/').pop() ?? cpuNodeName; - return propNodeId === short || propNodeId === cpuNodeName || short.includes(propNodeId) || propNodeId.includes(short); -} - -function percentile(sorted: number[], p: number): number { - const idx = Math.floor(sorted.length * p); - return sorted[Math.min(idx, sorted.length - 1)]; -} - const BUCKET_SIZE = 0.25; const ALL_BUCKETS = Array.from({ length: 49 }, (_, i) => i * BUCKET_SIZE); const toBucket = (offsetSec: number): number => Math.round(offsetSec / BUCKET_SIZE) * BUCKET_SIZE; @@ -54,6 +43,8 @@ interface NetworkIoChartProps { slot: number; annotations: AnnotationEvent[]; enabledAnnotations: Set; + highlight: HighlightRange | null; + onHighlight: (range: HighlightRange | null) => void; } const PHASE_BOUNDARY_COLORS = ['#22d3ee', '#22c55e', '#f59e0b']; @@ -71,9 +62,31 @@ export function NetworkIoChart({ slot, annotations, enabledAnnotations, + highlight, + onHighlight, }: NetworkIoChartProps): JSX.Element { const { CHART_CATEGORICAL_COLORS } = getDataVizColors(); + const [gridOffsets, setGridOffsets] = useState({ left: 60, right: 24, height: 350 }); + const handleChartReady = useCallback( + (instance: { + convertToPixel: (finder: { gridIndex: number }, value: number[]) => number[]; + getDom: () => HTMLElement | null; + }) => { + try { + const px0 = instance.convertToPixel({ gridIndex: 0 }, [0, 0]); + const px12 = instance.convertToPixel({ gridIndex: 0 }, [12, 0]); + const width = instance.getDom()?.clientWidth ?? 0; + if (px0 && px12 && width > 0) { + setGridOffsets({ left: Math.round(px0[0]), right: Math.round(width - px12[0]), height: Math.round(px0[1]) }); + } + } catch { + /* use defaults */ + } + }, + [] + ); + const series = useMemo(() => { if (data.length === 0) return [] as SeriesData[]; @@ -128,76 +141,6 @@ export function NetworkIoChart({ return chartSeries; }, [data, selectedNode, CHART_CATEGORICAL_COLORS]); - const markAreas = useMemo((): MarkAreaConfig[] => { - const areas: MarkAreaConfig[] = []; - - if (selectedNode) { - for (const anno of annotations) { - if (!enabledAnnotations.has(anno.type)) continue; - if (!anno.nodeName || !nodeMatches(selectedNode, anno.nodeName)) continue; - - const startSec = anno.timeMs / 1000; - if (startSec < 0 || startSec > 12) continue; - const color = ANNOTATION_COLORS[anno.type]; - const hasRange = anno.endMs != null && Math.abs(anno.endMs - anno.timeMs) > 10; - - if (hasRange) { - const endSec = Math.min(anno.endMs! / 1000, 12); - areas.push({ xStart: startSec, xEnd: endSec, color, opacity: 0.12 }); - } else { - areas.push({ - xStart: startSec - MIN_AREA_WIDTH_SEC / 2, - xEnd: startSec + MIN_AREA_WIDTH_SEC / 2, - color, - opacity: 0.3, - }); - } - } - } else { - const byType = new Map(); - for (const anno of annotations) { - if (!enabledAnnotations.has(anno.type)) continue; - if (!byType.has(anno.type)) byType.set(anno.type, []); - byType.get(anno.type)!.push(anno); - } - - for (const [type, events] of byType) { - const color = ANNOTATION_COLORS[type]; - const hasRanges = events.some(e => e.endMs != null); - - if (hasRanges) { - const starts = events.map(e => e.timeMs).sort((a, b) => a - b); - const ends = events.map(e => e.endMs ?? e.timeMs).sort((a, b) => a - b); - const startSec = starts[0] / 1000; - const endSec = percentile(ends, 0.95) / 1000; - if (startSec >= 0 && startSec <= 12) { - areas.push({ xStart: Math.max(0, startSec), xEnd: Math.min(12, endSec), color, opacity: 0.1 }); - } - } else { - const times = events.map(e => e.timeMs).sort((a, b) => a - b); - const minSec = times[0] / 1000; - const p95Sec = percentile(times, 0.95) / 1000; - if (minSec >= 0 && p95Sec <= 12) { - const width = p95Sec - minSec; - if (width < MIN_AREA_WIDTH_SEC) { - const medSec = percentile(times, 0.5) / 1000; - areas.push({ - xStart: medSec - MIN_AREA_WIDTH_SEC / 2, - xEnd: medSec + MIN_AREA_WIDTH_SEC / 2, - color, - opacity: 0.25, - }); - } else { - areas.push({ xStart: minSec, xEnd: p95Sec, color, opacity: 0.1 }); - } - } - } - } - } - - return areas; - }, [annotations, enabledAnnotations, selectedNode]); - const markLines = useMemo((): MarkLineConfig[] => { if (!enabledAnnotations.has('slot_phases')) return []; @@ -247,51 +190,83 @@ export function NetworkIoChart({ return ( {({ inModal }) => ( - `${v}s`, - }} - yAxis={{ - name: 'KB', - min: 0, - formatter: (v: number) => `${v.toFixed(0)} KB`, - }} - height={inModal ? 500 : 350} - showLegend - legendPosition="bottom" - markLines={markLines} - markAreas={markAreas} - syncGroup="slot-time" - tooltipFormatter={(params: unknown) => { - const items = (Array.isArray(params) ? params : [params]) as EChartsTooltipParam[]; - if (items.length === 0) return ''; - - const first = items[0]; - const xVal = Array.isArray(first.value) ? first.value[0] : first.axisValue; - const timeStr = typeof xVal === 'number' ? `${xVal.toFixed(2)}s` : `${xVal}s`; - - let html = `
`; - html += `
${timeStr}
`; - - for (const p of items) { - const val = Array.isArray(p.value) ? p.value[1] : p.value; - if (val == null) continue; - html += `
`; - html += `${p.marker}`; - html += `${p.seriesName}`; - html += `${Number(val).toFixed(1)} KB`; - html += `
`; - } - - html += `
`; - return html; - }} - /> + <> +
+ `${v}s`, + }} + yAxis={{ + name: 'KB', + min: 0, + formatter: (v: number) => `${v.toFixed(0)} KB`, + }} + height={inModal ? 500 : 350} + showLegend + legendPosition="bottom" + markLines={markLines} + syncGroup="slot-time" + onChartReady={handleChartReady} + tooltipFormatter={(params: unknown) => { + const items = (Array.isArray(params) ? params : [params]) as EChartsTooltipParam[]; + if (items.length === 0) return ''; + + const first = items[0]; + const xVal = Array.isArray(first.value) ? first.value[0] : first.axisValue; + const timeStr = typeof xVal === 'number' ? `${xVal.toFixed(2)}s` : `${xVal}s`; + + let html = `
`; + html += `
${timeStr}
`; + + for (const p of items) { + const val = Array.isArray(p.value) ? p.value[1] : p.value; + if (val == null) continue; + html += `
`; + html += `${p.marker}`; + html += `${p.seriesName}`; + html += `${Number(val).toFixed(1)} KB`; + html += `
`; + } + + html += `
`; + return html; + }} + /> + {highlight && ( +
+
+
+ )} +
+ + )} ); diff --git a/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx b/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx index dd12bf5cd..3f8444bbe 100644 --- a/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/NodeResourcesPanel.tsx @@ -29,6 +29,7 @@ import { type MemoryMetric, type AnnotationType, type AnnotationEvent, + type HighlightRange, } from './types'; export type { CpuMetric } from './types'; @@ -67,6 +68,7 @@ export function NodeResourcesPanel({ const [enabledAnnotations, setEnabledAnnotations] = useState>( () => new Set(['slot_phases', 'block', 'head', 'execution', 'data_columns']) ); + const [highlight, setHighlight] = useState(null); // Always fetch execution timing data so the toggle can show availability const { data: executionData } = useQuery({ @@ -400,6 +402,8 @@ export function NodeResourcesPanel({ slot={slot} annotations={annotations} enabledAnnotations={enabledAnnotations} + highlight={highlight} + onHighlight={setHighlight} />
diff --git a/src/pages/ethereum/slots/components/NodeResources/types.ts b/src/pages/ethereum/slots/components/NodeResources/types.ts index a70046e90..9e179026f 100644 --- a/src/pages/ethereum/slots/components/NodeResources/types.ts +++ b/src/pages/ethereum/slots/components/NodeResources/types.ts @@ -24,6 +24,12 @@ export const ANNOTATION_COLORS: Record = { slot_phases: '#6b7280', }; +export interface HighlightRange { + startFrac: number; + widthFrac: number; + color: string; +} + export const ANNOTATION_OPTIONS: { value: AnnotationType; label: string; description: string }[] = [ { value: 'slot_phases', label: 'Slot Phases', description: 'Block / Attestation / Aggregation phase boundaries' }, { value: 'block', label: 'Block Arrival', description: 'When block gossip was received' }, From 0c7882f88427c538fb67590f6dde8839421a9b5d Mon Sep 17 00:00:00 2001 From: Sam Calder-Mason Date: Fri, 13 Feb 2026 10:19:53 +1000 Subject: [PATCH 15/15] fix(slots): address node resources review findings and CI stability --- src/components/Charts/Globe/Globe.stories.tsx | 2 + src/components/Charts/Map/Map.stories.tsx | 2 + .../NodeResources/AnnotationSwimLanes.tsx | 83 +++++++++++-------- .../NodeResources/CpuUtilizationChart.tsx | 4 +- src/routes/ethereum/slots/$slot.tsx | 8 +- 5 files changed, 63 insertions(+), 36 deletions(-) diff --git a/src/components/Charts/Globe/Globe.stories.tsx b/src/components/Charts/Globe/Globe.stories.tsx index 96dfd580f..40a645bf7 100644 --- a/src/components/Charts/Globe/Globe.stories.tsx +++ b/src/components/Charts/Globe/Globe.stories.tsx @@ -7,6 +7,8 @@ import type { LineData, PointData } from './Globe.types'; const meta: Meta = { title: 'Components/Charts/Globe', component: GlobeChart, + // WebGL contexts are not reliable in headless CI browsers. + tags: ['test-exclude'], decorators: [ Story => (
diff --git a/src/components/Charts/Map/Map.stories.tsx b/src/components/Charts/Map/Map.stories.tsx index 298093d68..fab1011e7 100644 --- a/src/components/Charts/Map/Map.stories.tsx +++ b/src/components/Charts/Map/Map.stories.tsx @@ -6,6 +6,8 @@ import type { RouteData, PointData } from './Map.types'; const meta: Meta = { title: 'Components/Charts/Map', component: MapChart, + // WebGL contexts are not reliable in headless CI browsers. + tags: ['test-exclude'], decorators: [ Story => (
diff --git a/src/pages/ethereum/slots/components/NodeResources/AnnotationSwimLanes.tsx b/src/pages/ethereum/slots/components/NodeResources/AnnotationSwimLanes.tsx index 662115d82..e4147c617 100644 --- a/src/pages/ethereum/slots/components/NodeResources/AnnotationSwimLanes.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/AnnotationSwimLanes.tsx @@ -1,8 +1,15 @@ import { type JSX, useMemo } from 'react'; -import { ANNOTATION_COLORS, ANNOTATION_OPTIONS, type AnnotationType, type AnnotationEvent, type HighlightRange } from './types'; +import { + ANNOTATION_COLORS, + ANNOTATION_OPTIONS, + type AnnotationType, + type AnnotationEvent, + type HighlightRange, +} from './types'; /** Minimum visual width (fraction of 0–1) so point events remain clickable/visible */ const MIN_MARK_FRAC = 0.08 / 12; +const SLOT_DURATION_MS = 12_000; /** Annotation types rendered as swim lanes (slot_phases excluded – those stay as chart markLines) */ const LANE_TYPES: Exclude[] = ['block', 'head', 'execution', 'data_columns']; @@ -23,6 +30,10 @@ function percentile(sorted: number[], p: number): number { return sorted[Math.min(idx, sorted.length - 1)]; } +function clampFraction(value: number): number { + return Math.max(0, Math.min(1, value)); +} + interface AnnotationSwimLanesProps { annotations: AnnotationEvent[]; enabledAnnotations: Set; @@ -65,13 +76,15 @@ export function AnnotationSwimLanes({ if (anno.type !== laneType) continue; if (!anno.nodeName || !nodeMatches(anno.nodeName, selectedNode)) continue; - const startFrac = anno.timeMs / 12000; - if (startFrac < 0 || startFrac > 1) continue; - const hasRange = anno.endMs != null && Math.abs(anno.endMs - anno.timeMs) > 10; + const rawStartFrac = anno.timeMs / SLOT_DURATION_MS; + const rawEndFrac = (anno.endMs ?? anno.timeMs) / SLOT_DURATION_MS; + if (rawEndFrac < 0 || rawStartFrac > 1) continue; + + const startFrac = clampFraction(rawStartFrac); + const endFrac = clampFraction(rawEndFrac); if (hasRange) { - const endFrac = Math.min(anno.endMs! / 12000, 1); marks.push({ leftPct: startFrac * 100, widthPct: Math.max((endFrac - startFrac) * 100, MIN_MARK_FRAC * 100), @@ -97,39 +110,43 @@ export function AnnotationSwimLanes({ if (hasRanges) { const starts = events.map(e => e.timeMs).sort((a, b) => a - b); const ends = events.map(e => e.endMs ?? e.timeMs).sort((a, b) => a - b); - const startFrac = starts[0] / 12000; - const endFrac = Math.min(percentile(ends, 0.95) / 12000, 1); - if (startFrac >= 0 && startFrac <= 1) { + const rawStartFrac = starts[0] / SLOT_DURATION_MS; + const rawEndFrac = percentile(ends, 0.95) / SLOT_DURATION_MS; + if (rawEndFrac < 0 || rawStartFrac > 1) continue; + + const startFrac = clampFraction(rawStartFrac); + const endFrac = clampFraction(rawEndFrac); + marks.push({ + leftPct: startFrac * 100, + widthPct: Math.max((endFrac - startFrac) * 100, MIN_MARK_FRAC * 100), + color, + opacity: 0.5, + }); + } else { + const times = events.map(e => e.timeMs).sort((a, b) => a - b); + const rawMinFrac = times[0] / SLOT_DURATION_MS; + const rawP95Frac = percentile(times, 0.95) / SLOT_DURATION_MS; + if (rawP95Frac < 0 || rawMinFrac > 1) continue; + + const minFrac = clampFraction(rawMinFrac); + const p95Frac = clampFraction(rawP95Frac); + const width = p95Frac - minFrac; + if (width < MIN_MARK_FRAC) { + const medFrac = clampFraction(percentile(times, 0.5) / SLOT_DURATION_MS); marks.push({ - leftPct: Math.max(0, startFrac) * 100, - widthPct: Math.max((endFrac - startFrac) * 100, MIN_MARK_FRAC * 100), + leftPct: Math.max(0, medFrac - MIN_MARK_FRAC / 2) * 100, + widthPct: MIN_MARK_FRAC * 100, + color, + opacity: 0.7, + }); + } else { + marks.push({ + leftPct: minFrac * 100, + widthPct: (p95Frac - minFrac) * 100, color, opacity: 0.5, }); } - } else { - const times = events.map(e => e.timeMs).sort((a, b) => a - b); - const minFrac = times[0] / 12000; - const p95Frac = percentile(times, 0.95) / 12000; - if (minFrac >= 0 && p95Frac <= 1) { - const width = p95Frac - minFrac; - if (width < MIN_MARK_FRAC) { - const medFrac = percentile(times, 0.5) / 12000; - marks.push({ - leftPct: Math.max(0, medFrac - MIN_MARK_FRAC / 2) * 100, - widthPct: MIN_MARK_FRAC * 100, - color, - opacity: 0.7, - }); - } else { - marks.push({ - leftPct: minFrac * 100, - widthPct: (p95Frac - minFrac) * 100, - color, - opacity: 0.5, - }); - } - } } } diff --git a/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx b/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx index eb5e33aa4..03c6a2a7a 100644 --- a/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx +++ b/src/pages/ethereum/slots/components/NodeResources/CpuUtilizationChart.tsx @@ -180,7 +180,7 @@ export function CpuUtilizationChart({ chartSeries.push({ name: clLabel, - data: toPoints(clBuckets, b => b.meanVals), + data: toPoints(clBuckets, metricExtract), color: clColor, lineWidth: 2, showArea: true, @@ -190,7 +190,7 @@ export function CpuUtilizationChart({ chartSeries.push({ name: elLabel, - data: toPoints(elBuckets, b => b.meanVals), + data: toPoints(elBuckets, metricExtract), color: elColor, lineWidth: 2, showArea: true, diff --git a/src/routes/ethereum/slots/$slot.tsx b/src/routes/ethereum/slots/$slot.tsx index a711d0a09..0c644f83c 100644 --- a/src/routes/ethereum/slots/$slot.tsx +++ b/src/routes/ethereum/slots/$slot.tsx @@ -10,7 +10,13 @@ const slotSearchSchema = z.object({ node: z.string().optional(), metric: z.enum(['mean', 'min', 'max']).optional(), memMetric: z.enum(['vm_rss', 'rss_anon', 'rss_file', 'vm_swap']).optional(), - refNodes: z.coerce.boolean().optional(), + refNodes: z + .preprocess(value => { + if (value === 'true') return true; + if (value === 'false') return false; + return value; + }, z.boolean()) + .optional(), }); export const Route = createFileRoute('/ethereum/slots/$slot')({