diff --git a/buf.lock b/buf.lock index a7653dd2..5df8acde 100644 --- a/buf.lock +++ b/buf.lock @@ -2,5 +2,5 @@ version: v2 deps: - name: buf.build/googleapis/googleapis - commit: 72c8614f3bd0466ea67931ef2c43d608 - digest: b5:13efeea24e633fd45327390bdee941207a8727e96cf01affb84c1e4100fd8f48a42bbd508df11930cd2884629bafad685df1ac3111bc78cdaefcd38c9371c6b1 + commit: 004180b77378443887d3b55cabc00384 + digest: b5:e8f475fe3330f31f5fd86ac689093bcd274e19611a09db91f41d637cb9197881ce89882b94d13a58738e53c91c6e4bae7dc1feba85f590164c975a89e25115dc diff --git a/migrations/033_fct_peer_head_last_30m.down.sql b/migrations/033_fct_peer_head_last_30m.down.sql new file mode 100644 index 00000000..ae30b99a --- /dev/null +++ b/migrations/033_fct_peer_head_last_30m.down.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS `${NETWORK_NAME}`.fct_peer_head_last_30m ON CLUSTER '{cluster}'; +DROP TABLE IF EXISTS `${NETWORK_NAME}`.fct_peer_head_last_30m_local ON CLUSTER '{cluster}'; diff --git a/migrations/033_fct_peer_head_last_30m.up.sql b/migrations/033_fct_peer_head_last_30m.up.sql new file mode 100644 index 00000000..dfff36c8 --- /dev/null +++ b/migrations/033_fct_peer_head_last_30m.up.sql @@ -0,0 +1,27 @@ +CREATE TABLE `${NETWORK_NAME}`.fct_peer_head_last_30m_local ON CLUSTER '{cluster}' ( + `updated_date_time` DateTime COMMENT 'Timestamp when the record was last updated' CODEC(DoubleDelta, ZSTD(1)), + `head_slot` UInt32 COMMENT 'The head slot reported by peers' CODEC(DoubleDelta, ZSTD(1)), + `head_root` String COMMENT 'The head block root reported by peers (unknown if not available)' CODEC(ZSTD(1)), + `peer_count` UInt32 COMMENT 'Total number of peers at this head' CODEC(ZSTD(1)), + `count_by_client` Map(String, UInt32) COMMENT 'Peer count breakdown by client implementation' CODEC(ZSTD(1)), + `count_by_country` Map(String, UInt32) COMMENT 'Peer count breakdown by country' CODEC(ZSTD(1)), + `count_by_continent` Map(String, UInt32) COMMENT 'Peer count breakdown by continent code' CODEC(ZSTD(1)), + `count_by_fork_digest` Map(String, UInt32) COMMENT 'Peer count breakdown by fork digest' CODEC(ZSTD(1)), + `count_by_platform` Map(String, UInt32) COMMENT 'Peer count breakdown by platform (os)' CODEC(ZSTD(1)), + `count_by_finalized_epoch` Map(String, UInt32) COMMENT 'Peer count breakdown by finalized epoch' CODEC(ZSTD(1)) +) ENGINE = ReplicatedReplacingMergeTree( + '/clickhouse/{installation}/{cluster}/tables/{shard}/{database}/{table}', + '{replica}', + `updated_date_time` +) PARTITION BY toStartOfMonth(updated_date_time) +ORDER BY (`head_slot`, `head_root`) +SETTINGS + deduplicate_merge_projection_mode = 'rebuild' +COMMENT 'Aggregated peer head distribution from the last 30 minutes of handle_status events'; + +CREATE TABLE `${NETWORK_NAME}`.fct_peer_head_last_30m ON CLUSTER '{cluster}' AS `${NETWORK_NAME}`.fct_peer_head_last_30m_local ENGINE = Distributed( + '{cluster}', + '${NETWORK_NAME}', + fct_peer_head_last_30m_local, + cityHash64(`head_slot`, `head_root`) +); diff --git a/migrations/034_int_peer_head.down.sql b/migrations/034_int_peer_head.down.sql new file mode 100644 index 00000000..9cb87b84 --- /dev/null +++ b/migrations/034_int_peer_head.down.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS `${NETWORK_NAME}`.int_peer_head ON CLUSTER '{cluster}'; +DROP TABLE IF EXISTS `${NETWORK_NAME}`.int_peer_head_local ON CLUSTER '{cluster}'; diff --git a/migrations/034_int_peer_head.up.sql b/migrations/034_int_peer_head.up.sql new file mode 100644 index 00000000..a10b78a5 --- /dev/null +++ b/migrations/034_int_peer_head.up.sql @@ -0,0 +1,30 @@ +CREATE TABLE `${NETWORK_NAME}`.int_peer_head_local ON CLUSTER '{cluster}' ( + `updated_date_time` DateTime COMMENT 'Timestamp when the record was last updated' CODEC(DoubleDelta, ZSTD(1)), + `event_date_time` DateTime COMMENT 'Timestamp when the status was observed' CODEC(DoubleDelta, ZSTD(1)), + `peer_id_unique_key` String COMMENT 'Unique key for the peer' CODEC(ZSTD(1)), + `head_slot` UInt32 COMMENT 'The head slot reported by the peer' CODEC(DoubleDelta, ZSTD(1)), + `head_root` String COMMENT 'The head block root reported by the peer' CODEC(ZSTD(1)), + `fork_digest` LowCardinality(String) COMMENT 'The fork digest reported by the peer' CODEC(ZSTD(1)), + `finalized_epoch` Nullable(UInt32) COMMENT 'The finalized epoch reported by the peer' CODEC(ZSTD(1)), + `client` LowCardinality(String) COMMENT 'Client implementation (e.g., lighthouse, prysm)' CODEC(ZSTD(1)), + `client_version` LowCardinality(String) COMMENT 'Client version' CODEC(ZSTD(1)), + `platform` LowCardinality(String) COMMENT 'Platform/OS' CODEC(ZSTD(1)), + `country` LowCardinality(String) COMMENT 'Country name' CODEC(ZSTD(1)), + `country_code` LowCardinality(String) COMMENT 'Country code' CODEC(ZSTD(1)), + `continent_code` LowCardinality(String) COMMENT 'Continent code' CODEC(ZSTD(1)) +) ENGINE = ReplicatedReplacingMergeTree( + '/clickhouse/{installation}/{cluster}/tables/{shard}/{database}/{table}', + '{replica}', + `updated_date_time` +) PARTITION BY toStartOfDay(event_date_time) +ORDER BY (`head_slot`, `peer_id_unique_key`) +SETTINGS + deduplicate_merge_projection_mode = 'rebuild' +COMMENT 'Per-peer head observations from handle_status events, enriched with metadata'; + +CREATE TABLE `${NETWORK_NAME}`.int_peer_head ON CLUSTER '{cluster}' AS `${NETWORK_NAME}`.int_peer_head_local ENGINE = Distributed( + '{cluster}', + '${NETWORK_NAME}', + int_peer_head_local, + cityHash64(`head_slot`, `peer_id_unique_key`) +); diff --git a/models/external/libp2p_handle_status.sql b/models/external/libp2p_handle_status.sql new file mode 100644 index 00000000..22da57b6 --- /dev/null +++ b/models/external/libp2p_handle_status.sql @@ -0,0 +1,25 @@ +--- +table: libp2p_handle_status +cache: + incremental_scan_interval: 5s + full_scan_interval: 24h +interval: + type: datetime + lag: 60 +--- +SELECT + {{ if .cache.is_incremental_scan }} + '{{ .cache.previous_min }}' as min, + {{ else }} + toUnixTimestamp(min(event_date_time)) as min, + {{ end }} + toUnixTimestamp(max(event_date_time)) as max +FROM {{ .self.helpers.from }} +WHERE + meta_network_name = '{{ .env.NETWORK }}' + +{{ if .cache.is_incremental_scan }} + AND event_date_time >= fromUnixTimestamp({{ .cache.previous_max }}) +{{ else }} + AND event_date_time >= fromUnixTimestamp({{ default "0" .env.EXTERNAL_MODEL_MIN_TIMESTAMP }}) +{{ end }} diff --git a/models/external/libp2p_synthetic_heartbeat.sql b/models/external/libp2p_synthetic_heartbeat.sql new file mode 100644 index 00000000..0727dcf2 --- /dev/null +++ b/models/external/libp2p_synthetic_heartbeat.sql @@ -0,0 +1,25 @@ +--- +table: libp2p_synthetic_heartbeat +cache: + incremental_scan_interval: 5s + full_scan_interval: 24h +interval: + type: datetime + lag: 60 +--- +SELECT + {{ if .cache.is_incremental_scan }} + '{{ .cache.previous_min }}' as min, + {{ else }} + toUnixTimestamp(min(event_date_time)) as min, + {{ end }} + toUnixTimestamp(max(event_date_time)) as max +FROM {{ .self.helpers.from }} +WHERE + meta_network_name = '{{ .env.NETWORK }}' + +{{ if .cache.is_incremental_scan }} + AND event_date_time >= fromUnixTimestamp({{ .cache.previous_max }}) +{{ else }} + AND event_date_time >= fromUnixTimestamp({{ default "0" .env.EXTERNAL_MODEL_MIN_TIMESTAMP }}) +{{ end }} diff --git a/models/transformations/fct_peer_head_last_30m.sql b/models/transformations/fct_peer_head_last_30m.sql new file mode 100644 index 00000000..77dee1ce --- /dev/null +++ b/models/transformations/fct_peer_head_last_30m.sql @@ -0,0 +1,58 @@ +--- +table: fct_peer_head_last_30m +type: scheduled +schedule: "@every 30s" +tags: + - libp2p + - peer + - head +dependencies: + - "{{transformation}}.int_peer_head" +--- +INSERT INTO `{{ .self.database }}`.`{{ .self.table }}` +WITH +-- Get the lookback interval from env, defaulting to 30 minutes +lookback_minutes AS ( + SELECT {{ default "30" .env.PEER_HEAD_LOOKBACK_MINUTES }} AS minutes +), + +-- Get the latest observation per peer from int_peer_head within the lookback window +latest_peer_head AS ( + SELECT + peer_id_unique_key, + argMax(head_slot, event_date_time) AS head_slot, + argMax(head_root, event_date_time) AS head_root, + argMax(fork_digest, event_date_time) AS fork_digest, + argMax(finalized_epoch, event_date_time) AS finalized_epoch, + argMax(client, event_date_time) AS client, + argMax(platform, event_date_time) AS platform, + argMax(continent_code, event_date_time) AS continent_code, + argMax(country, event_date_time) AS country + FROM `{{ .self.database }}`.int_peer_head FINAL + WHERE event_date_time >= NOW() - INTERVAL (SELECT minutes FROM lookback_minutes) MINUTE + GROUP BY peer_id_unique_key +) + +-- Aggregate by head_slot/head_root to get counts +SELECT + fromUnixTimestamp({{ .task.start }}) AS updated_date_time, + head_slot, + head_root, + count(*) AS peer_count, + sumMap(map(client, toUInt32(1))) AS count_by_client, + sumMap(map(country, toUInt32(1))) AS count_by_country, + sumMap(map(continent_code, toUInt32(1))) AS count_by_continent, + sumMap(map(fork_digest, toUInt32(1))) AS count_by_fork_digest, + sumMap(map(platform, toUInt32(1))) AS count_by_platform, + sumMap(map(toString(coalesce(finalized_epoch, toUInt32(0))), toUInt32(1))) AS count_by_finalized_epoch +FROM latest_peer_head +WHERE head_slot IS NOT NULL +GROUP BY head_slot, head_root +ORDER BY peer_count DESC; + +-- Remove previous snapshot to keep only the latest +DELETE FROM `{{ .self.database }}`.`{{ .self.table }}{{ if .clickhouse.cluster }}{{ .clickhouse.local_suffix }}{{ end }}` +{{ if .clickhouse.cluster }} +ON CLUSTER '{{ .clickhouse.cluster }}' +{{ end }} +WHERE updated_date_time != fromUnixTimestamp({{ .task.start }}); diff --git a/models/transformations/int_peer_head.sql b/models/transformations/int_peer_head.sql new file mode 100644 index 00000000..a9b2bb61 --- /dev/null +++ b/models/transformations/int_peer_head.sql @@ -0,0 +1,103 @@ +--- +table: int_peer_head +type: incremental +interval: + type: datetime + max: 3600 +schedules: + forwardfill: "@every 30s" + backfill: "@every 60s" +tags: + - libp2p + - peer + - head +dependencies: + - "{{external}}.libp2p_handle_status" + - "{{external}}.libp2p_synthetic_heartbeat" +--- +INSERT INTO `{{ .self.database }}`.`{{ .self.table }}` +WITH +-- Extract peer head data from handle_status events +-- For outbound: response_* is the peer's data +-- For inbound: request_* is the peer's data +peer_status AS ( + SELECT + event_date_time, + peer_id_unique_key, + CASE + WHEN direction = 'outbound' THEN response_head_slot + ELSE request_head_slot + END AS head_slot, + CASE + WHEN direction = 'outbound' THEN response_head_root + ELSE request_head_root + END AS head_root, + CASE + WHEN direction = 'outbound' THEN response_fork_digest + ELSE request_fork_digest + END AS fork_digest, + CASE + WHEN direction = 'outbound' THEN response_finalized_epoch + ELSE request_finalized_epoch + END AS finalized_epoch + FROM {{ index .dep "{{external}}" "libp2p_handle_status" "helpers" "from" }} + WHERE + meta_network_name = '{{ .env.NETWORK }}' + AND event_date_time BETWEEN fromUnixTimestamp({{ .bounds.start }}) AND fromUnixTimestamp({{ .bounds.end }}) + AND error IS NULL + AND ( + (direction = 'outbound' AND response_head_slot IS NOT NULL) OR + (direction != 'outbound' AND request_head_slot IS NOT NULL) OR + (direction IS NULL AND request_head_slot IS NOT NULL) + ) +), + +-- Get peer metadata from synthetic heartbeat (using a wider window for metadata) +peer_metadata AS ( + SELECT + remote_peer_id_unique_key, + argMax(remote_agent_implementation, event_date_time) AS client, + argMax(remote_agent_version, event_date_time) AS client_version, + argMax(remote_agent_platform, event_date_time) AS platform, + argMax(remote_geo_country, event_date_time) AS country, + argMax(remote_geo_country_code, event_date_time) AS country_code, + argMax(remote_geo_continent_code, event_date_time) AS continent_code + FROM {{ index .dep "{{external}}" "libp2p_synthetic_heartbeat" "helpers" "from" }} + WHERE + meta_network_name = '{{ .env.NETWORK }}' + -- Use a wider window to ensure we have metadata for peers + AND event_date_time BETWEEN fromUnixTimestamp({{ .bounds.start }}) - INTERVAL 1 HOUR AND fromUnixTimestamp({{ .bounds.end }}) + GROUP BY remote_peer_id_unique_key +) + +-- Join status with metadata and deduplicate to latest per (head_slot, peer) +SELECT + fromUnixTimestamp({{ .task.start }}) AS updated_date_time, + argMax(s.event_date_time, s.event_date_time) AS event_date_time, + s.peer_id_unique_key, + s.head_slot, + -- Normalize head_root: ensure 0x prefix, remove null bytes + argMax( + if( + nullIf(replaceAll(s.head_root, '\0', ''), '') IS NULL, + 'unknown', + if( + startsWith(replaceAll(s.head_root, '\0', ''), '0x'), + replaceAll(s.head_root, '\0', ''), + concat('0x', replaceAll(s.head_root, '\0', '')) + ) + ), + s.event_date_time + ) AS head_root, + argMax(coalesce(nullIf(s.fork_digest, ''), 'unknown'), s.event_date_time) AS fork_digest, + argMax(s.finalized_epoch, s.event_date_time) AS finalized_epoch, + argMax(coalesce(nullIf(m.client, ''), 'unknown'), s.event_date_time) AS client, + argMax(coalesce(nullIf(m.client_version, ''), 'unknown'), s.event_date_time) AS client_version, + argMax(coalesce(nullIf(m.platform, ''), 'unknown'), s.event_date_time) AS platform, + argMax(coalesce(nullIf(m.country, ''), 'unknown'), s.event_date_time) AS country, + argMax(coalesce(nullIf(m.country_code, ''), 'unknown'), s.event_date_time) AS country_code, + argMax(coalesce(nullIf(m.continent_code, ''), 'unknown'), s.event_date_time) AS continent_code +FROM peer_status s +LEFT JOIN peer_metadata m ON s.peer_id_unique_key = m.remote_peer_id_unique_key +WHERE s.head_slot IS NOT NULL +GROUP BY s.head_slot, s.peer_id_unique_key; diff --git a/pkg/proto/clickhouse/fct_peer_head_last_30m.go b/pkg/proto/clickhouse/fct_peer_head_last_30m.go new file mode 100644 index 00000000..c054a773 --- /dev/null +++ b/pkg/proto/clickhouse/fct_peer_head_last_30m.go @@ -0,0 +1,448 @@ +// Code generated by clickhouse-proto-gen. DO NOT EDIT. +// SQL query builder for fct_peer_head_last_30m + +package clickhouse + +import ( + "fmt" +) + +// BuildListFctPeerHeadLast30MQuery constructs a parameterized SQL query from a ListFctPeerHeadLast30MRequest +func BuildListFctPeerHeadLast30MQuery(req *ListFctPeerHeadLast30MRequest, options ...QueryOption) (SQLQuery, error) { + // Validate that at least one primary key is provided + // Primary keys can come from base table or projections + if req.HeadSlot == nil { + return SQLQuery{}, fmt.Errorf("primary key field head_slot is required") + } + + // Build query using QueryBuilder + qb := NewQueryBuilder() + + // Add primary key filter + switch filter := req.HeadSlot.Filter.(type) { + case *UInt32Filter_Eq: + qb.AddCondition("head_slot", "=", filter.Eq) + case *UInt32Filter_Ne: + qb.AddCondition("head_slot", "!=", filter.Ne) + case *UInt32Filter_Lt: + qb.AddCondition("head_slot", "<", filter.Lt) + case *UInt32Filter_Lte: + qb.AddCondition("head_slot", "<=", filter.Lte) + case *UInt32Filter_Gt: + qb.AddCondition("head_slot", ">", filter.Gt) + case *UInt32Filter_Gte: + qb.AddCondition("head_slot", ">=", filter.Gte) + case *UInt32Filter_Between: + qb.AddBetweenCondition("head_slot", filter.Between.Min, filter.Between.Max.GetValue()) + case *UInt32Filter_In: + if len(filter.In.Values) > 0 { + qb.AddInCondition("head_slot", UInt32SliceToInterface(filter.In.Values)) + } + case *UInt32Filter_NotIn: + if len(filter.NotIn.Values) > 0 { + qb.AddNotInCondition("head_slot", UInt32SliceToInterface(filter.NotIn.Values)) + } + default: + // Unsupported filter type + } + + // Add filter for column: updated_date_time + if req.UpdatedDateTime != nil { + switch filter := req.UpdatedDateTime.Filter.(type) { + case *UInt32Filter_Eq: + qb.AddCondition("updated_date_time", "=", DateTimeValue{filter.Eq}) + case *UInt32Filter_Ne: + qb.AddCondition("updated_date_time", "!=", DateTimeValue{filter.Ne}) + case *UInt32Filter_Lt: + qb.AddCondition("updated_date_time", "<", DateTimeValue{filter.Lt}) + case *UInt32Filter_Lte: + qb.AddCondition("updated_date_time", "<=", DateTimeValue{filter.Lte}) + case *UInt32Filter_Gt: + qb.AddCondition("updated_date_time", ">", DateTimeValue{filter.Gt}) + case *UInt32Filter_Gte: + qb.AddCondition("updated_date_time", ">=", DateTimeValue{filter.Gte}) + case *UInt32Filter_Between: + qb.AddBetweenCondition("updated_date_time", DateTimeValue{filter.Between.Min}, DateTimeValue{filter.Between.Max.GetValue()}) + case *UInt32Filter_In: + if len(filter.In.Values) > 0 { + converted := make([]interface{}, len(filter.In.Values)) + for i, v := range filter.In.Values { + converted[i] = DateTimeValue{v} + } + qb.AddInCondition("updated_date_time", converted) + } + case *UInt32Filter_NotIn: + if len(filter.NotIn.Values) > 0 { + converted := make([]interface{}, len(filter.NotIn.Values)) + for i, v := range filter.NotIn.Values { + converted[i] = DateTimeValue{v} + } + qb.AddNotInCondition("updated_date_time", converted) + } + default: + // Unsupported filter type + } + } + + // Add filter for column: head_root + if req.HeadRoot != nil { + switch filter := req.HeadRoot.Filter.(type) { + case *StringFilter_Eq: + qb.AddCondition("head_root", "=", filter.Eq) + case *StringFilter_Ne: + qb.AddCondition("head_root", "!=", filter.Ne) + case *StringFilter_Contains: + qb.AddLikeCondition("head_root", "%" + filter.Contains + "%") + case *StringFilter_StartsWith: + qb.AddLikeCondition("head_root", filter.StartsWith + "%") + case *StringFilter_EndsWith: + qb.AddLikeCondition("head_root", "%" + filter.EndsWith) + case *StringFilter_Like: + qb.AddLikeCondition("head_root", filter.Like) + case *StringFilter_NotLike: + qb.AddNotLikeCondition("head_root", filter.NotLike) + case *StringFilter_In: + if len(filter.In.Values) > 0 { + qb.AddInCondition("head_root", StringSliceToInterface(filter.In.Values)) + } + case *StringFilter_NotIn: + if len(filter.NotIn.Values) > 0 { + qb.AddNotInCondition("head_root", StringSliceToInterface(filter.NotIn.Values)) + } + default: + // Unsupported filter type + } + } + + // Add filter for column: peer_count + if req.PeerCount != nil { + switch filter := req.PeerCount.Filter.(type) { + case *UInt32Filter_Eq: + qb.AddCondition("peer_count", "=", filter.Eq) + case *UInt32Filter_Ne: + qb.AddCondition("peer_count", "!=", filter.Ne) + case *UInt32Filter_Lt: + qb.AddCondition("peer_count", "<", filter.Lt) + case *UInt32Filter_Lte: + qb.AddCondition("peer_count", "<=", filter.Lte) + case *UInt32Filter_Gt: + qb.AddCondition("peer_count", ">", filter.Gt) + case *UInt32Filter_Gte: + qb.AddCondition("peer_count", ">=", filter.Gte) + case *UInt32Filter_Between: + qb.AddBetweenCondition("peer_count", filter.Between.Min, filter.Between.Max.GetValue()) + case *UInt32Filter_In: + if len(filter.In.Values) > 0 { + qb.AddInCondition("peer_count", UInt32SliceToInterface(filter.In.Values)) + } + case *UInt32Filter_NotIn: + if len(filter.NotIn.Values) > 0 { + qb.AddNotInCondition("peer_count", UInt32SliceToInterface(filter.NotIn.Values)) + } + default: + // Unsupported filter type + } + } + + // Add filter for column: count_by_client + if req.CountByClient != nil { + switch filter := req.CountByClient.Filter.(type) { + case *MapStringUInt32Filter_KeyValue: + // Handle key-value filter with UInt32 values + switch kvFilter := filter.KeyValue.ValueFilter.Filter.(type) { + case *UInt32Filter_Eq: + qb.AddMapKeyCondition("count_by_client", filter.KeyValue.Key, "=", kvFilter.Eq) + case *UInt32Filter_Ne: + qb.AddMapKeyCondition("count_by_client", filter.KeyValue.Key, "!=", kvFilter.Ne) + case *UInt32Filter_Lt: + qb.AddMapKeyCondition("count_by_client", filter.KeyValue.Key, "<", kvFilter.Lt) + case *UInt32Filter_Lte: + qb.AddMapKeyCondition("count_by_client", filter.KeyValue.Key, "<=", kvFilter.Lte) + case *UInt32Filter_Gt: + qb.AddMapKeyCondition("count_by_client", filter.KeyValue.Key, ">", kvFilter.Gt) + case *UInt32Filter_Gte: + qb.AddMapKeyCondition("count_by_client", filter.KeyValue.Key, ">=", kvFilter.Gte) + case *UInt32Filter_Between: + qb.AddMapKeyBetweenCondition("count_by_client", filter.KeyValue.Key, kvFilter.Between.Min, kvFilter.Between.Max) + } + case *MapStringUInt32Filter_HasKey: + qb.AddMapContainsCondition("count_by_client", filter.HasKey) + case *MapStringUInt32Filter_NotHasKey: + qb.AddNotMapContainsCondition("count_by_client", filter.NotHasKey) + case *MapStringUInt32Filter_HasAnyKey: + if len(filter.HasAnyKey.Values) > 0 { + qb.AddMapContainsAnyCondition("count_by_client", filter.HasAnyKey.Values) + } + case *MapStringUInt32Filter_HasAllKeys: + if len(filter.HasAllKeys.Values) > 0 { + for _, key := range filter.HasAllKeys.Values { + qb.AddMapContainsCondition("count_by_client", key) + } + } + default: + // Unsupported filter type + } + } + + // Add filter for column: count_by_country + if req.CountByCountry != nil { + switch filter := req.CountByCountry.Filter.(type) { + case *MapStringUInt32Filter_KeyValue: + // Handle key-value filter with UInt32 values + switch kvFilter := filter.KeyValue.ValueFilter.Filter.(type) { + case *UInt32Filter_Eq: + qb.AddMapKeyCondition("count_by_country", filter.KeyValue.Key, "=", kvFilter.Eq) + case *UInt32Filter_Ne: + qb.AddMapKeyCondition("count_by_country", filter.KeyValue.Key, "!=", kvFilter.Ne) + case *UInt32Filter_Lt: + qb.AddMapKeyCondition("count_by_country", filter.KeyValue.Key, "<", kvFilter.Lt) + case *UInt32Filter_Lte: + qb.AddMapKeyCondition("count_by_country", filter.KeyValue.Key, "<=", kvFilter.Lte) + case *UInt32Filter_Gt: + qb.AddMapKeyCondition("count_by_country", filter.KeyValue.Key, ">", kvFilter.Gt) + case *UInt32Filter_Gte: + qb.AddMapKeyCondition("count_by_country", filter.KeyValue.Key, ">=", kvFilter.Gte) + case *UInt32Filter_Between: + qb.AddMapKeyBetweenCondition("count_by_country", filter.KeyValue.Key, kvFilter.Between.Min, kvFilter.Between.Max) + } + case *MapStringUInt32Filter_HasKey: + qb.AddMapContainsCondition("count_by_country", filter.HasKey) + case *MapStringUInt32Filter_NotHasKey: + qb.AddNotMapContainsCondition("count_by_country", filter.NotHasKey) + case *MapStringUInt32Filter_HasAnyKey: + if len(filter.HasAnyKey.Values) > 0 { + qb.AddMapContainsAnyCondition("count_by_country", filter.HasAnyKey.Values) + } + case *MapStringUInt32Filter_HasAllKeys: + if len(filter.HasAllKeys.Values) > 0 { + for _, key := range filter.HasAllKeys.Values { + qb.AddMapContainsCondition("count_by_country", key) + } + } + default: + // Unsupported filter type + } + } + + // Add filter for column: count_by_continent + if req.CountByContinent != nil { + switch filter := req.CountByContinent.Filter.(type) { + case *MapStringUInt32Filter_KeyValue: + // Handle key-value filter with UInt32 values + switch kvFilter := filter.KeyValue.ValueFilter.Filter.(type) { + case *UInt32Filter_Eq: + qb.AddMapKeyCondition("count_by_continent", filter.KeyValue.Key, "=", kvFilter.Eq) + case *UInt32Filter_Ne: + qb.AddMapKeyCondition("count_by_continent", filter.KeyValue.Key, "!=", kvFilter.Ne) + case *UInt32Filter_Lt: + qb.AddMapKeyCondition("count_by_continent", filter.KeyValue.Key, "<", kvFilter.Lt) + case *UInt32Filter_Lte: + qb.AddMapKeyCondition("count_by_continent", filter.KeyValue.Key, "<=", kvFilter.Lte) + case *UInt32Filter_Gt: + qb.AddMapKeyCondition("count_by_continent", filter.KeyValue.Key, ">", kvFilter.Gt) + case *UInt32Filter_Gte: + qb.AddMapKeyCondition("count_by_continent", filter.KeyValue.Key, ">=", kvFilter.Gte) + case *UInt32Filter_Between: + qb.AddMapKeyBetweenCondition("count_by_continent", filter.KeyValue.Key, kvFilter.Between.Min, kvFilter.Between.Max) + } + case *MapStringUInt32Filter_HasKey: + qb.AddMapContainsCondition("count_by_continent", filter.HasKey) + case *MapStringUInt32Filter_NotHasKey: + qb.AddNotMapContainsCondition("count_by_continent", filter.NotHasKey) + case *MapStringUInt32Filter_HasAnyKey: + if len(filter.HasAnyKey.Values) > 0 { + qb.AddMapContainsAnyCondition("count_by_continent", filter.HasAnyKey.Values) + } + case *MapStringUInt32Filter_HasAllKeys: + if len(filter.HasAllKeys.Values) > 0 { + for _, key := range filter.HasAllKeys.Values { + qb.AddMapContainsCondition("count_by_continent", key) + } + } + default: + // Unsupported filter type + } + } + + // Add filter for column: count_by_fork_digest + if req.CountByForkDigest != nil { + switch filter := req.CountByForkDigest.Filter.(type) { + case *MapStringUInt32Filter_KeyValue: + // Handle key-value filter with UInt32 values + switch kvFilter := filter.KeyValue.ValueFilter.Filter.(type) { + case *UInt32Filter_Eq: + qb.AddMapKeyCondition("count_by_fork_digest", filter.KeyValue.Key, "=", kvFilter.Eq) + case *UInt32Filter_Ne: + qb.AddMapKeyCondition("count_by_fork_digest", filter.KeyValue.Key, "!=", kvFilter.Ne) + case *UInt32Filter_Lt: + qb.AddMapKeyCondition("count_by_fork_digest", filter.KeyValue.Key, "<", kvFilter.Lt) + case *UInt32Filter_Lte: + qb.AddMapKeyCondition("count_by_fork_digest", filter.KeyValue.Key, "<=", kvFilter.Lte) + case *UInt32Filter_Gt: + qb.AddMapKeyCondition("count_by_fork_digest", filter.KeyValue.Key, ">", kvFilter.Gt) + case *UInt32Filter_Gte: + qb.AddMapKeyCondition("count_by_fork_digest", filter.KeyValue.Key, ">=", kvFilter.Gte) + case *UInt32Filter_Between: + qb.AddMapKeyBetweenCondition("count_by_fork_digest", filter.KeyValue.Key, kvFilter.Between.Min, kvFilter.Between.Max) + } + case *MapStringUInt32Filter_HasKey: + qb.AddMapContainsCondition("count_by_fork_digest", filter.HasKey) + case *MapStringUInt32Filter_NotHasKey: + qb.AddNotMapContainsCondition("count_by_fork_digest", filter.NotHasKey) + case *MapStringUInt32Filter_HasAnyKey: + if len(filter.HasAnyKey.Values) > 0 { + qb.AddMapContainsAnyCondition("count_by_fork_digest", filter.HasAnyKey.Values) + } + case *MapStringUInt32Filter_HasAllKeys: + if len(filter.HasAllKeys.Values) > 0 { + for _, key := range filter.HasAllKeys.Values { + qb.AddMapContainsCondition("count_by_fork_digest", key) + } + } + default: + // Unsupported filter type + } + } + + // Add filter for column: count_by_platform + if req.CountByPlatform != nil { + switch filter := req.CountByPlatform.Filter.(type) { + case *MapStringUInt32Filter_KeyValue: + // Handle key-value filter with UInt32 values + switch kvFilter := filter.KeyValue.ValueFilter.Filter.(type) { + case *UInt32Filter_Eq: + qb.AddMapKeyCondition("count_by_platform", filter.KeyValue.Key, "=", kvFilter.Eq) + case *UInt32Filter_Ne: + qb.AddMapKeyCondition("count_by_platform", filter.KeyValue.Key, "!=", kvFilter.Ne) + case *UInt32Filter_Lt: + qb.AddMapKeyCondition("count_by_platform", filter.KeyValue.Key, "<", kvFilter.Lt) + case *UInt32Filter_Lte: + qb.AddMapKeyCondition("count_by_platform", filter.KeyValue.Key, "<=", kvFilter.Lte) + case *UInt32Filter_Gt: + qb.AddMapKeyCondition("count_by_platform", filter.KeyValue.Key, ">", kvFilter.Gt) + case *UInt32Filter_Gte: + qb.AddMapKeyCondition("count_by_platform", filter.KeyValue.Key, ">=", kvFilter.Gte) + case *UInt32Filter_Between: + qb.AddMapKeyBetweenCondition("count_by_platform", filter.KeyValue.Key, kvFilter.Between.Min, kvFilter.Between.Max) + } + case *MapStringUInt32Filter_HasKey: + qb.AddMapContainsCondition("count_by_platform", filter.HasKey) + case *MapStringUInt32Filter_NotHasKey: + qb.AddNotMapContainsCondition("count_by_platform", filter.NotHasKey) + case *MapStringUInt32Filter_HasAnyKey: + if len(filter.HasAnyKey.Values) > 0 { + qb.AddMapContainsAnyCondition("count_by_platform", filter.HasAnyKey.Values) + } + case *MapStringUInt32Filter_HasAllKeys: + if len(filter.HasAllKeys.Values) > 0 { + for _, key := range filter.HasAllKeys.Values { + qb.AddMapContainsCondition("count_by_platform", key) + } + } + default: + // Unsupported filter type + } + } + + // Add filter for column: count_by_finalized_epoch + if req.CountByFinalizedEpoch != nil { + switch filter := req.CountByFinalizedEpoch.Filter.(type) { + case *MapStringUInt32Filter_KeyValue: + // Handle key-value filter with UInt32 values + switch kvFilter := filter.KeyValue.ValueFilter.Filter.(type) { + case *UInt32Filter_Eq: + qb.AddMapKeyCondition("count_by_finalized_epoch", filter.KeyValue.Key, "=", kvFilter.Eq) + case *UInt32Filter_Ne: + qb.AddMapKeyCondition("count_by_finalized_epoch", filter.KeyValue.Key, "!=", kvFilter.Ne) + case *UInt32Filter_Lt: + qb.AddMapKeyCondition("count_by_finalized_epoch", filter.KeyValue.Key, "<", kvFilter.Lt) + case *UInt32Filter_Lte: + qb.AddMapKeyCondition("count_by_finalized_epoch", filter.KeyValue.Key, "<=", kvFilter.Lte) + case *UInt32Filter_Gt: + qb.AddMapKeyCondition("count_by_finalized_epoch", filter.KeyValue.Key, ">", kvFilter.Gt) + case *UInt32Filter_Gte: + qb.AddMapKeyCondition("count_by_finalized_epoch", filter.KeyValue.Key, ">=", kvFilter.Gte) + case *UInt32Filter_Between: + qb.AddMapKeyBetweenCondition("count_by_finalized_epoch", filter.KeyValue.Key, kvFilter.Between.Min, kvFilter.Between.Max) + } + case *MapStringUInt32Filter_HasKey: + qb.AddMapContainsCondition("count_by_finalized_epoch", filter.HasKey) + case *MapStringUInt32Filter_NotHasKey: + qb.AddNotMapContainsCondition("count_by_finalized_epoch", filter.NotHasKey) + case *MapStringUInt32Filter_HasAnyKey: + if len(filter.HasAnyKey.Values) > 0 { + qb.AddMapContainsAnyCondition("count_by_finalized_epoch", filter.HasAnyKey.Values) + } + case *MapStringUInt32Filter_HasAllKeys: + if len(filter.HasAllKeys.Values) > 0 { + for _, key := range filter.HasAllKeys.Values { + qb.AddMapContainsCondition("count_by_finalized_epoch", key) + } + } + default: + // Unsupported filter type + } + } + + // Handle pagination per AIP-132 + // Validate page size + if req.PageSize < 0 { + return SQLQuery{}, fmt.Errorf("page_size must be non-negative, got %d", req.PageSize) + } + if req.PageSize > 10000 { + return SQLQuery{}, fmt.Errorf("page_size must not exceed %d, got %d", 10000, req.PageSize) + } + + var limit, offset uint32 + limit = 100 // Default page size + if req.PageSize > 0 { + limit = uint32(req.PageSize) + } + if req.PageToken != "" { + decodedOffset, err := DecodePageToken(req.PageToken) + if err != nil { + return SQLQuery{}, fmt.Errorf("invalid page_token: %w", err) + } + offset = decodedOffset + } + + // Handle custom ordering if provided + var orderByClause string + if req.OrderBy != "" { + validFields := []string{"updated_date_time", "head_slot", "head_root", "peer_count", "count_by_client", "count_by_country", "count_by_continent", "count_by_fork_digest", "count_by_platform", "count_by_finalized_epoch"} + orderFields, err := ParseOrderBy(req.OrderBy, validFields) + if err != nil { + return SQLQuery{}, fmt.Errorf("invalid order_by: %w", err) + } + orderByClause = BuildOrderByClause(orderFields) + } else { + // Default sorting by primary key + orderByClause = " ORDER BY head_slot" + ", head_root" + } + + // Build column list + columns := []string{"toUnixTimestamp(`updated_date_time`) AS `updated_date_time`", "head_slot", "head_root", "peer_count", "count_by_client", "count_by_country", "count_by_continent", "count_by_fork_digest", "count_by_platform", "count_by_finalized_epoch"} + + return BuildParameterizedQuery("fct_peer_head_last_30m", columns, qb, orderByClause, limit, offset, options...) +} + +// BuildGetFctPeerHeadLast30MQuery constructs a parameterized SQL query from a GetFctPeerHeadLast30MRequest +func BuildGetFctPeerHeadLast30MQuery(req *GetFctPeerHeadLast30MRequest, options ...QueryOption) (SQLQuery, error) { + // Validate primary key is provided + if req.HeadSlot == 0 { + return SQLQuery{}, fmt.Errorf("primary key field head_slot is required") + } + + // Build query with primary key condition + qb := NewQueryBuilder() + qb.AddCondition("head_slot", "=", req.HeadSlot) + + // Build ORDER BY clause + orderByClause := " ORDER BY head_slot, head_root" + + // Build column list + columns := []string{"toUnixTimestamp(`updated_date_time`) AS `updated_date_time`", "head_slot", "head_root", "peer_count", "count_by_client", "count_by_country", "count_by_continent", "count_by_fork_digest", "count_by_platform", "count_by_finalized_epoch"} + + // Return single record + return BuildParameterizedQuery("fct_peer_head_last_30m", columns, qb, orderByClause, 1, 0, options...) +} diff --git a/pkg/proto/clickhouse/fct_peer_head_last_30m.pb.go b/pkg/proto/clickhouse/fct_peer_head_last_30m.pb.go new file mode 100644 index 00000000..796eb87e --- /dev/null +++ b/pkg/proto/clickhouse/fct_peer_head_last_30m.pb.go @@ -0,0 +1,795 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.34.2 +// protoc (unknown) +// source: fct_peer_head_last_30m.proto + +package clickhouse + +import ( + _ "github.com/ethpandaops/xatu-cbt/pkg/proto/clickhouse/clickhouse" + _ "google.golang.org/genproto/googleapis/api/annotations" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type FctPeerHeadLast30M struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Timestamp when the record was last updated + UpdatedDateTime uint32 `protobuf:"varint,11,opt,name=updated_date_time,json=updatedDateTime,proto3" json:"updated_date_time,omitempty"` + // The head slot reported by peers + HeadSlot uint32 `protobuf:"varint,12,opt,name=head_slot,json=headSlot,proto3" json:"head_slot,omitempty"` + // The head block root reported by peers (unknown if not available) + HeadRoot string `protobuf:"bytes,13,opt,name=head_root,json=headRoot,proto3" json:"head_root,omitempty"` + // Total number of peers at this head + PeerCount uint32 `protobuf:"varint,14,opt,name=peer_count,json=peerCount,proto3" json:"peer_count,omitempty"` + // Peer count breakdown by client implementation + CountByClient map[string]uint32 `protobuf:"bytes,15,rep,name=count_by_client,json=countByClient,proto3" json:"count_by_client,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + // Peer count breakdown by country + CountByCountry map[string]uint32 `protobuf:"bytes,16,rep,name=count_by_country,json=countByCountry,proto3" json:"count_by_country,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + // Peer count breakdown by continent code + CountByContinent map[string]uint32 `protobuf:"bytes,17,rep,name=count_by_continent,json=countByContinent,proto3" json:"count_by_continent,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + // Peer count breakdown by fork digest + CountByForkDigest map[string]uint32 `protobuf:"bytes,18,rep,name=count_by_fork_digest,json=countByForkDigest,proto3" json:"count_by_fork_digest,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + // Peer count breakdown by platform (os) + CountByPlatform map[string]uint32 `protobuf:"bytes,19,rep,name=count_by_platform,json=countByPlatform,proto3" json:"count_by_platform,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + // Peer count breakdown by finalized epoch + CountByFinalizedEpoch map[string]uint32 `protobuf:"bytes,20,rep,name=count_by_finalized_epoch,json=countByFinalizedEpoch,proto3" json:"count_by_finalized_epoch,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` +} + +func (x *FctPeerHeadLast30M) Reset() { + *x = FctPeerHeadLast30M{} + if protoimpl.UnsafeEnabled { + mi := &file_fct_peer_head_last_30m_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FctPeerHeadLast30M) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FctPeerHeadLast30M) ProtoMessage() {} + +func (x *FctPeerHeadLast30M) ProtoReflect() protoreflect.Message { + mi := &file_fct_peer_head_last_30m_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FctPeerHeadLast30M.ProtoReflect.Descriptor instead. +func (*FctPeerHeadLast30M) Descriptor() ([]byte, []int) { + return file_fct_peer_head_last_30m_proto_rawDescGZIP(), []int{0} +} + +func (x *FctPeerHeadLast30M) GetUpdatedDateTime() uint32 { + if x != nil { + return x.UpdatedDateTime + } + return 0 +} + +func (x *FctPeerHeadLast30M) GetHeadSlot() uint32 { + if x != nil { + return x.HeadSlot + } + return 0 +} + +func (x *FctPeerHeadLast30M) GetHeadRoot() string { + if x != nil { + return x.HeadRoot + } + return "" +} + +func (x *FctPeerHeadLast30M) GetPeerCount() uint32 { + if x != nil { + return x.PeerCount + } + return 0 +} + +func (x *FctPeerHeadLast30M) GetCountByClient() map[string]uint32 { + if x != nil { + return x.CountByClient + } + return nil +} + +func (x *FctPeerHeadLast30M) GetCountByCountry() map[string]uint32 { + if x != nil { + return x.CountByCountry + } + return nil +} + +func (x *FctPeerHeadLast30M) GetCountByContinent() map[string]uint32 { + if x != nil { + return x.CountByContinent + } + return nil +} + +func (x *FctPeerHeadLast30M) GetCountByForkDigest() map[string]uint32 { + if x != nil { + return x.CountByForkDigest + } + return nil +} + +func (x *FctPeerHeadLast30M) GetCountByPlatform() map[string]uint32 { + if x != nil { + return x.CountByPlatform + } + return nil +} + +func (x *FctPeerHeadLast30M) GetCountByFinalizedEpoch() map[string]uint32 { + if x != nil { + return x.CountByFinalizedEpoch + } + return nil +} + +// Request for listing fct_peer_head_last_30m records +type ListFctPeerHeadLast30MRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Filter by head_slot - The head slot reported by peers (PRIMARY KEY - required) + HeadSlot *UInt32Filter `protobuf:"bytes,1,opt,name=head_slot,json=headSlot,proto3" json:"head_slot,omitempty"` + // Filter by head_root - The head block root reported by peers (unknown if not available) (ORDER BY column 2 - optional) + HeadRoot *StringFilter `protobuf:"bytes,2,opt,name=head_root,json=headRoot,proto3" json:"head_root,omitempty"` + // Filter by updated_date_time - Timestamp when the record was last updated (optional) + UpdatedDateTime *UInt32Filter `protobuf:"bytes,3,opt,name=updated_date_time,json=updatedDateTime,proto3" json:"updated_date_time,omitempty"` + // Filter by peer_count - Total number of peers at this head (optional) + PeerCount *UInt32Filter `protobuf:"bytes,4,opt,name=peer_count,json=peerCount,proto3" json:"peer_count,omitempty"` + // Filter by count_by_client - Peer count breakdown by client implementation (optional) + CountByClient *MapStringUInt32Filter `protobuf:"bytes,5,opt,name=count_by_client,json=countByClient,proto3" json:"count_by_client,omitempty"` + // Filter by count_by_country - Peer count breakdown by country (optional) + CountByCountry *MapStringUInt32Filter `protobuf:"bytes,6,opt,name=count_by_country,json=countByCountry,proto3" json:"count_by_country,omitempty"` + // Filter by count_by_continent - Peer count breakdown by continent code (optional) + CountByContinent *MapStringUInt32Filter `protobuf:"bytes,7,opt,name=count_by_continent,json=countByContinent,proto3" json:"count_by_continent,omitempty"` + // Filter by count_by_fork_digest - Peer count breakdown by fork digest (optional) + CountByForkDigest *MapStringUInt32Filter `protobuf:"bytes,8,opt,name=count_by_fork_digest,json=countByForkDigest,proto3" json:"count_by_fork_digest,omitempty"` + // Filter by count_by_platform - Peer count breakdown by platform (os) (optional) + CountByPlatform *MapStringUInt32Filter `protobuf:"bytes,9,opt,name=count_by_platform,json=countByPlatform,proto3" json:"count_by_platform,omitempty"` + // Filter by count_by_finalized_epoch - Peer count breakdown by finalized epoch (optional) + CountByFinalizedEpoch *MapStringUInt32Filter `protobuf:"bytes,10,opt,name=count_by_finalized_epoch,json=countByFinalizedEpoch,proto3" json:"count_by_finalized_epoch,omitempty"` + // The maximum number of fct_peer_head_last_30m to return. + // If unspecified, at most 100 items will be returned. + // The maximum value is 10000; values above 10000 will be coerced to 10000. + PageSize int32 `protobuf:"varint,11,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + // A page token, received from a previous `ListFctPeerHeadLast30m` call. + // Provide this to retrieve the subsequent page. + PageToken string `protobuf:"bytes,12,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"` + // 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. + OrderBy string `protobuf:"bytes,13,opt,name=order_by,json=orderBy,proto3" json:"order_by,omitempty"` +} + +func (x *ListFctPeerHeadLast30MRequest) Reset() { + *x = ListFctPeerHeadLast30MRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_fct_peer_head_last_30m_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListFctPeerHeadLast30MRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListFctPeerHeadLast30MRequest) ProtoMessage() {} + +func (x *ListFctPeerHeadLast30MRequest) ProtoReflect() protoreflect.Message { + mi := &file_fct_peer_head_last_30m_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListFctPeerHeadLast30MRequest.ProtoReflect.Descriptor instead. +func (*ListFctPeerHeadLast30MRequest) Descriptor() ([]byte, []int) { + return file_fct_peer_head_last_30m_proto_rawDescGZIP(), []int{1} +} + +func (x *ListFctPeerHeadLast30MRequest) GetHeadSlot() *UInt32Filter { + if x != nil { + return x.HeadSlot + } + return nil +} + +func (x *ListFctPeerHeadLast30MRequest) GetHeadRoot() *StringFilter { + if x != nil { + return x.HeadRoot + } + return nil +} + +func (x *ListFctPeerHeadLast30MRequest) GetUpdatedDateTime() *UInt32Filter { + if x != nil { + return x.UpdatedDateTime + } + return nil +} + +func (x *ListFctPeerHeadLast30MRequest) GetPeerCount() *UInt32Filter { + if x != nil { + return x.PeerCount + } + return nil +} + +func (x *ListFctPeerHeadLast30MRequest) GetCountByClient() *MapStringUInt32Filter { + if x != nil { + return x.CountByClient + } + return nil +} + +func (x *ListFctPeerHeadLast30MRequest) GetCountByCountry() *MapStringUInt32Filter { + if x != nil { + return x.CountByCountry + } + return nil +} + +func (x *ListFctPeerHeadLast30MRequest) GetCountByContinent() *MapStringUInt32Filter { + if x != nil { + return x.CountByContinent + } + return nil +} + +func (x *ListFctPeerHeadLast30MRequest) GetCountByForkDigest() *MapStringUInt32Filter { + if x != nil { + return x.CountByForkDigest + } + return nil +} + +func (x *ListFctPeerHeadLast30MRequest) GetCountByPlatform() *MapStringUInt32Filter { + if x != nil { + return x.CountByPlatform + } + return nil +} + +func (x *ListFctPeerHeadLast30MRequest) GetCountByFinalizedEpoch() *MapStringUInt32Filter { + if x != nil { + return x.CountByFinalizedEpoch + } + return nil +} + +func (x *ListFctPeerHeadLast30MRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *ListFctPeerHeadLast30MRequest) GetPageToken() string { + if x != nil { + return x.PageToken + } + return "" +} + +func (x *ListFctPeerHeadLast30MRequest) GetOrderBy() string { + if x != nil { + return x.OrderBy + } + return "" +} + +// Response for listing fct_peer_head_last_30m records +type ListFctPeerHeadLast30MResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The list of fct_peer_head_last_30m. + FctPeerHeadLast_30M []*FctPeerHeadLast30M `protobuf:"bytes,1,rep,name=fct_peer_head_last_30m,json=fctPeerHeadLast30m,proto3" json:"fct_peer_head_last_30m,omitempty"` + // A token, which can be sent as `page_token` to retrieve the next page. + // If this field is omitted, there are no subsequent pages. + NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` +} + +func (x *ListFctPeerHeadLast30MResponse) Reset() { + *x = ListFctPeerHeadLast30MResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_fct_peer_head_last_30m_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListFctPeerHeadLast30MResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListFctPeerHeadLast30MResponse) ProtoMessage() {} + +func (x *ListFctPeerHeadLast30MResponse) ProtoReflect() protoreflect.Message { + mi := &file_fct_peer_head_last_30m_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListFctPeerHeadLast30MResponse.ProtoReflect.Descriptor instead. +func (*ListFctPeerHeadLast30MResponse) Descriptor() ([]byte, []int) { + return file_fct_peer_head_last_30m_proto_rawDescGZIP(), []int{2} +} + +func (x *ListFctPeerHeadLast30MResponse) GetFctPeerHeadLast_30M() []*FctPeerHeadLast30M { + if x != nil { + return x.FctPeerHeadLast_30M + } + return nil +} + +func (x *ListFctPeerHeadLast30MResponse) GetNextPageToken() string { + if x != nil { + return x.NextPageToken + } + return "" +} + +// Request for getting a single fct_peer_head_last_30m record by primary key +type GetFctPeerHeadLast30MRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The head slot reported by peers + HeadSlot uint32 `protobuf:"varint,1,opt,name=head_slot,json=headSlot,proto3" json:"head_slot,omitempty"` // Primary key (required) +} + +func (x *GetFctPeerHeadLast30MRequest) Reset() { + *x = GetFctPeerHeadLast30MRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_fct_peer_head_last_30m_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetFctPeerHeadLast30MRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFctPeerHeadLast30MRequest) ProtoMessage() {} + +func (x *GetFctPeerHeadLast30MRequest) ProtoReflect() protoreflect.Message { + mi := &file_fct_peer_head_last_30m_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFctPeerHeadLast30MRequest.ProtoReflect.Descriptor instead. +func (*GetFctPeerHeadLast30MRequest) Descriptor() ([]byte, []int) { + return file_fct_peer_head_last_30m_proto_rawDescGZIP(), []int{3} +} + +func (x *GetFctPeerHeadLast30MRequest) GetHeadSlot() uint32 { + if x != nil { + return x.HeadSlot + } + return 0 +} + +// Response for getting a single fct_peer_head_last_30m record +type GetFctPeerHeadLast30MResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Item *FctPeerHeadLast30M `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` +} + +func (x *GetFctPeerHeadLast30MResponse) Reset() { + *x = GetFctPeerHeadLast30MResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_fct_peer_head_last_30m_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetFctPeerHeadLast30MResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFctPeerHeadLast30MResponse) ProtoMessage() {} + +func (x *GetFctPeerHeadLast30MResponse) ProtoReflect() protoreflect.Message { + mi := &file_fct_peer_head_last_30m_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFctPeerHeadLast30MResponse.ProtoReflect.Descriptor instead. +func (*GetFctPeerHeadLast30MResponse) Descriptor() ([]byte, []int) { + return file_fct_peer_head_last_30m_proto_rawDescGZIP(), []int{4} +} + +func (x *GetFctPeerHeadLast30MResponse) GetItem() *FctPeerHeadLast30M { + if x != nil { + return x.Item + } + return nil +} + +var File_fct_peer_head_last_30m_proto protoreflect.FileDescriptor + +var file_fct_peer_head_last_30m_proto_rawDesc = []byte{ + 0x0a, 0x1c, 0x66, 0x63, 0x74, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x5f, + 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x33, 0x30, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, + 0x63, 0x62, 0x74, 0x1a, 0x0c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, + 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, + 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x1a, 0x1c, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x68, 0x6f, 0x75, 0x73, 0x65, 0x2f, 0x61, 0x6e, 0x6e, + 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe7, + 0x08, 0x0a, 0x12, 0x46, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, 0x4c, 0x61, + 0x73, 0x74, 0x33, 0x30, 0x6d, 0x12, 0x2a, 0x0a, 0x11, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x0f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, + 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x18, 0x0c, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x68, 0x65, 0x61, 0x64, 0x53, 0x6c, 0x6f, 0x74, 0x12, 0x1b, + 0x0a, 0x09, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x68, 0x65, 0x61, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x70, + 0x65, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x09, 0x70, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x52, 0x0a, 0x0f, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x5f, 0x62, 0x79, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x0f, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x46, 0x63, 0x74, 0x50, 0x65, 0x65, + 0x72, 0x48, 0x65, 0x61, 0x64, 0x4c, 0x61, 0x73, 0x74, 0x33, 0x30, 0x6d, 0x2e, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x42, 0x79, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x0d, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x55, + 0x0a, 0x10, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x62, 0x79, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x72, 0x79, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x46, + 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, 0x4c, 0x61, 0x73, 0x74, 0x33, 0x30, + 0x6d, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x5b, 0x0a, 0x12, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x62, + 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x11, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x2d, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x46, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, + 0x65, 0x61, 0x64, 0x4c, 0x61, 0x73, 0x74, 0x33, 0x30, 0x6d, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x42, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x10, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x65, + 0x6e, 0x74, 0x12, 0x5f, 0x0a, 0x14, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x62, 0x79, 0x5f, 0x66, + 0x6f, 0x72, 0x6b, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x12, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x2e, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x46, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, 0x65, + 0x61, 0x64, 0x4c, 0x61, 0x73, 0x74, 0x33, 0x30, 0x6d, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x42, + 0x79, 0x46, 0x6f, 0x72, 0x6b, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x11, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x46, 0x6f, 0x72, 0x6b, 0x44, 0x69, 0x67, + 0x65, 0x73, 0x74, 0x12, 0x58, 0x0a, 0x11, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x62, 0x79, 0x5f, + 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x13, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, + 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x46, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, + 0x4c, 0x61, 0x73, 0x74, 0x33, 0x30, 0x6d, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x50, + 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x42, 0x79, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x6b, 0x0a, + 0x18, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x62, 0x79, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, + 0x7a, 0x65, 0x64, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x14, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x32, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x46, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, 0x65, 0x61, + 0x64, 0x4c, 0x61, 0x73, 0x74, 0x33, 0x30, 0x6d, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, + 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x15, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x46, 0x69, 0x6e, 0x61, + 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x1a, 0x40, 0x0a, 0x12, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x42, 0x79, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x41, 0x0a, 0x13, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, + 0x43, 0x0a, 0x15, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6e, + 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x44, 0x0a, 0x16, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x46, + 0x6f, 0x72, 0x6b, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x42, 0x0a, 0x14, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x42, 0x79, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x48, + 0x0a, 0x1a, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, + 0x65, 0x64, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd5, 0x06, 0x0a, 0x1d, 0x4c, 0x69, 0x73, + 0x74, 0x46, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, 0x4c, 0x61, 0x73, 0x74, + 0x33, 0x30, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x09, 0x68, 0x65, + 0x61, 0x64, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, + 0x63, 0x62, 0x74, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x42, 0x12, 0xe0, 0x41, 0x02, 0x9a, 0xb5, 0x18, 0x0b, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, + 0x5f, 0x6b, 0x65, 0x79, 0x52, 0x08, 0x68, 0x65, 0x61, 0x64, 0x53, 0x6c, 0x6f, 0x74, 0x12, 0x33, + 0x0a, 0x09, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x46, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x08, 0x68, 0x65, 0x61, 0x64, 0x52, + 0x6f, 0x6f, 0x74, 0x12, 0x42, 0x0a, 0x11, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x64, + 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, + 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x0f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x44, + 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x0a, 0x70, 0x65, 0x65, 0x72, 0x5f, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x62, + 0x74, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x03, + 0xe0, 0x41, 0x01, 0x52, 0x09, 0x70, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x47, + 0x0a, 0x0f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x62, 0x79, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x4d, 0x61, + 0x70, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x0d, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, + 0x79, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x49, 0x0a, 0x10, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x5f, 0x62, 0x79, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x4d, 0x61, 0x70, 0x53, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x03, 0xe0, + 0x41, 0x01, 0x52, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x4d, 0x0a, 0x12, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x62, 0x79, 0x5f, 0x63, + 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x4d, 0x61, 0x70, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x55, 0x49, + 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, + 0x10, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x65, 0x6e, + 0x74, 0x12, 0x50, 0x0a, 0x14, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x62, 0x79, 0x5f, 0x66, 0x6f, + 0x72, 0x6b, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x4d, 0x61, 0x70, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x55, + 0x49, 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x03, 0xe0, 0x41, 0x01, + 0x52, 0x11, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x46, 0x6f, 0x72, 0x6b, 0x44, 0x69, 0x67, + 0x65, 0x73, 0x74, 0x12, 0x4b, 0x0a, 0x11, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x62, 0x79, 0x5f, + 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x4d, 0x61, 0x70, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x55, 0x49, + 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, + 0x0f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, + 0x12, 0x58, 0x0a, 0x18, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x62, 0x79, 0x5f, 0x66, 0x69, 0x6e, + 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x4d, 0x61, 0x70, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x03, + 0xe0, 0x41, 0x01, 0x52, 0x15, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x79, 0x46, 0x69, 0x6e, 0x61, + 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x20, 0x0a, 0x09, 0x70, 0x61, + 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x42, 0x03, 0xe0, + 0x41, 0x01, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0a, + 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x12, 0x1e, 0x0a, 0x08, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x62, 0x79, 0x18, 0x0d, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x07, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x42, 0x79, + 0x22, 0x95, 0x01, 0x0a, 0x1e, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, + 0x48, 0x65, 0x61, 0x64, 0x4c, 0x61, 0x73, 0x74, 0x33, 0x30, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x16, 0x66, 0x63, 0x74, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x5f, + 0x68, 0x65, 0x61, 0x64, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x33, 0x30, 0x6d, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x46, 0x63, 0x74, 0x50, 0x65, 0x65, + 0x72, 0x48, 0x65, 0x61, 0x64, 0x4c, 0x61, 0x73, 0x74, 0x33, 0x30, 0x6d, 0x52, 0x12, 0x66, 0x63, + 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, 0x4c, 0x61, 0x73, 0x74, 0x33, 0x30, 0x6d, + 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, + 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x3b, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x46, + 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, 0x4c, 0x61, 0x73, 0x74, 0x33, 0x30, + 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x65, 0x61, 0x64, + 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x68, 0x65, 0x61, + 0x64, 0x53, 0x6c, 0x6f, 0x74, 0x22, 0x4c, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x46, 0x63, 0x74, 0x50, + 0x65, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, 0x4c, 0x61, 0x73, 0x74, 0x33, 0x30, 0x6d, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x46, 0x63, 0x74, 0x50, 0x65, + 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, 0x4c, 0x61, 0x73, 0x74, 0x33, 0x30, 0x6d, 0x52, 0x04, 0x69, + 0x74, 0x65, 0x6d, 0x32, 0x97, 0x02, 0x0a, 0x19, 0x46, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, + 0x65, 0x61, 0x64, 0x4c, 0x61, 0x73, 0x74, 0x33, 0x30, 0x6d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x77, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x22, 0x2e, 0x63, 0x62, 0x74, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x46, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, 0x4c, + 0x61, 0x73, 0x74, 0x33, 0x30, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, + 0x63, 0x62, 0x74, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, + 0x65, 0x61, 0x64, 0x4c, 0x61, 0x73, 0x74, 0x33, 0x30, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x12, 0x1e, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x76, 0x31, 0x2f, 0x66, 0x63, 0x74, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x68, 0x65, 0x61, + 0x64, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x33, 0x30, 0x6d, 0x12, 0x80, 0x01, 0x0a, 0x03, 0x47, + 0x65, 0x74, 0x12, 0x21, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x63, 0x74, 0x50, + 0x65, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, 0x4c, 0x61, 0x73, 0x74, 0x33, 0x30, 0x6d, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x46, + 0x63, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, 0x4c, 0x61, 0x73, 0x74, 0x33, 0x30, + 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x32, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x2c, 0x12, 0x2a, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x66, 0x63, 0x74, 0x5f, 0x70, + 0x65, 0x65, 0x72, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x33, 0x30, + 0x6d, 0x2f, 0x7b, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x7d, 0x42, 0x36, 0x5a, + 0x34, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x74, 0x68, 0x70, + 0x61, 0x6e, 0x64, 0x61, 0x6f, 0x70, 0x73, 0x2f, 0x78, 0x61, 0x74, 0x75, 0x2d, 0x63, 0x62, 0x74, + 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6c, 0x69, 0x63, 0x6b, + 0x68, 0x6f, 0x75, 0x73, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_fct_peer_head_last_30m_proto_rawDescOnce sync.Once + file_fct_peer_head_last_30m_proto_rawDescData = file_fct_peer_head_last_30m_proto_rawDesc +) + +func file_fct_peer_head_last_30m_proto_rawDescGZIP() []byte { + file_fct_peer_head_last_30m_proto_rawDescOnce.Do(func() { + file_fct_peer_head_last_30m_proto_rawDescData = protoimpl.X.CompressGZIP(file_fct_peer_head_last_30m_proto_rawDescData) + }) + return file_fct_peer_head_last_30m_proto_rawDescData +} + +var file_fct_peer_head_last_30m_proto_msgTypes = make([]protoimpl.MessageInfo, 11) +var file_fct_peer_head_last_30m_proto_goTypes = []any{ + (*FctPeerHeadLast30M)(nil), // 0: cbt.FctPeerHeadLast30m + (*ListFctPeerHeadLast30MRequest)(nil), // 1: cbt.ListFctPeerHeadLast30mRequest + (*ListFctPeerHeadLast30MResponse)(nil), // 2: cbt.ListFctPeerHeadLast30mResponse + (*GetFctPeerHeadLast30MRequest)(nil), // 3: cbt.GetFctPeerHeadLast30mRequest + (*GetFctPeerHeadLast30MResponse)(nil), // 4: cbt.GetFctPeerHeadLast30mResponse + nil, // 5: cbt.FctPeerHeadLast30m.CountByClientEntry + nil, // 6: cbt.FctPeerHeadLast30m.CountByCountryEntry + nil, // 7: cbt.FctPeerHeadLast30m.CountByContinentEntry + nil, // 8: cbt.FctPeerHeadLast30m.CountByForkDigestEntry + nil, // 9: cbt.FctPeerHeadLast30m.CountByPlatformEntry + nil, // 10: cbt.FctPeerHeadLast30m.CountByFinalizedEpochEntry + (*UInt32Filter)(nil), // 11: cbt.UInt32Filter + (*StringFilter)(nil), // 12: cbt.StringFilter + (*MapStringUInt32Filter)(nil), // 13: cbt.MapStringUInt32Filter +} +var file_fct_peer_head_last_30m_proto_depIdxs = []int32{ + 5, // 0: cbt.FctPeerHeadLast30m.count_by_client:type_name -> cbt.FctPeerHeadLast30m.CountByClientEntry + 6, // 1: cbt.FctPeerHeadLast30m.count_by_country:type_name -> cbt.FctPeerHeadLast30m.CountByCountryEntry + 7, // 2: cbt.FctPeerHeadLast30m.count_by_continent:type_name -> cbt.FctPeerHeadLast30m.CountByContinentEntry + 8, // 3: cbt.FctPeerHeadLast30m.count_by_fork_digest:type_name -> cbt.FctPeerHeadLast30m.CountByForkDigestEntry + 9, // 4: cbt.FctPeerHeadLast30m.count_by_platform:type_name -> cbt.FctPeerHeadLast30m.CountByPlatformEntry + 10, // 5: cbt.FctPeerHeadLast30m.count_by_finalized_epoch:type_name -> cbt.FctPeerHeadLast30m.CountByFinalizedEpochEntry + 11, // 6: cbt.ListFctPeerHeadLast30mRequest.head_slot:type_name -> cbt.UInt32Filter + 12, // 7: cbt.ListFctPeerHeadLast30mRequest.head_root:type_name -> cbt.StringFilter + 11, // 8: cbt.ListFctPeerHeadLast30mRequest.updated_date_time:type_name -> cbt.UInt32Filter + 11, // 9: cbt.ListFctPeerHeadLast30mRequest.peer_count:type_name -> cbt.UInt32Filter + 13, // 10: cbt.ListFctPeerHeadLast30mRequest.count_by_client:type_name -> cbt.MapStringUInt32Filter + 13, // 11: cbt.ListFctPeerHeadLast30mRequest.count_by_country:type_name -> cbt.MapStringUInt32Filter + 13, // 12: cbt.ListFctPeerHeadLast30mRequest.count_by_continent:type_name -> cbt.MapStringUInt32Filter + 13, // 13: cbt.ListFctPeerHeadLast30mRequest.count_by_fork_digest:type_name -> cbt.MapStringUInt32Filter + 13, // 14: cbt.ListFctPeerHeadLast30mRequest.count_by_platform:type_name -> cbt.MapStringUInt32Filter + 13, // 15: cbt.ListFctPeerHeadLast30mRequest.count_by_finalized_epoch:type_name -> cbt.MapStringUInt32Filter + 0, // 16: cbt.ListFctPeerHeadLast30mResponse.fct_peer_head_last_30m:type_name -> cbt.FctPeerHeadLast30m + 0, // 17: cbt.GetFctPeerHeadLast30mResponse.item:type_name -> cbt.FctPeerHeadLast30m + 1, // 18: cbt.FctPeerHeadLast30mService.List:input_type -> cbt.ListFctPeerHeadLast30mRequest + 3, // 19: cbt.FctPeerHeadLast30mService.Get:input_type -> cbt.GetFctPeerHeadLast30mRequest + 2, // 20: cbt.FctPeerHeadLast30mService.List:output_type -> cbt.ListFctPeerHeadLast30mResponse + 4, // 21: cbt.FctPeerHeadLast30mService.Get:output_type -> cbt.GetFctPeerHeadLast30mResponse + 20, // [20:22] is the sub-list for method output_type + 18, // [18:20] is the sub-list for method input_type + 18, // [18:18] is the sub-list for extension type_name + 18, // [18:18] is the sub-list for extension extendee + 0, // [0:18] is the sub-list for field type_name +} + +func init() { file_fct_peer_head_last_30m_proto_init() } +func file_fct_peer_head_last_30m_proto_init() { + if File_fct_peer_head_last_30m_proto != nil { + return + } + file_common_proto_init() + if !protoimpl.UnsafeEnabled { + file_fct_peer_head_last_30m_proto_msgTypes[0].Exporter = func(v any, i int) any { + switch v := v.(*FctPeerHeadLast30M); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_fct_peer_head_last_30m_proto_msgTypes[1].Exporter = func(v any, i int) any { + switch v := v.(*ListFctPeerHeadLast30MRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_fct_peer_head_last_30m_proto_msgTypes[2].Exporter = func(v any, i int) any { + switch v := v.(*ListFctPeerHeadLast30MResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_fct_peer_head_last_30m_proto_msgTypes[3].Exporter = func(v any, i int) any { + switch v := v.(*GetFctPeerHeadLast30MRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_fct_peer_head_last_30m_proto_msgTypes[4].Exporter = func(v any, i int) any { + switch v := v.(*GetFctPeerHeadLast30MResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_fct_peer_head_last_30m_proto_rawDesc, + NumEnums: 0, + NumMessages: 11, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_fct_peer_head_last_30m_proto_goTypes, + DependencyIndexes: file_fct_peer_head_last_30m_proto_depIdxs, + MessageInfos: file_fct_peer_head_last_30m_proto_msgTypes, + }.Build() + File_fct_peer_head_last_30m_proto = out.File + file_fct_peer_head_last_30m_proto_rawDesc = nil + file_fct_peer_head_last_30m_proto_goTypes = nil + file_fct_peer_head_last_30m_proto_depIdxs = nil +} diff --git a/pkg/proto/clickhouse/fct_peer_head_last_30m.proto b/pkg/proto/clickhouse/fct_peer_head_last_30m.proto new file mode 100644 index 00000000..decc185c --- /dev/null +++ b/pkg/proto/clickhouse/fct_peer_head_last_30m.proto @@ -0,0 +1,108 @@ +syntax = "proto3"; + +package cbt; + +import "common.proto"; +import "google/api/annotations.proto"; +import "google/api/field_behavior.proto"; +import "clickhouse/annotations.proto"; + +option go_package = "github.com/ethpandaops/xatu-cbt/pkg/proto/clickhouse"; +// Aggregated peer head distribution from the last 30 minutes of handle_status events + +message FctPeerHeadLast30m { + // Timestamp when the record was last updated + uint32 updated_date_time = 11; + // The head slot reported by peers + uint32 head_slot = 12; + // The head block root reported by peers (unknown if not available) + string head_root = 13; + // Total number of peers at this head + uint32 peer_count = 14; + // Peer count breakdown by client implementation + map count_by_client = 15; + // Peer count breakdown by country + map count_by_country = 16; + // Peer count breakdown by continent code + map count_by_continent = 17; + // Peer count breakdown by fork digest + map count_by_fork_digest = 18; + // Peer count breakdown by platform (os) + map count_by_platform = 19; + // Peer count breakdown by finalized epoch + map count_by_finalized_epoch = 20; +} + +// Request for listing fct_peer_head_last_30m records +message ListFctPeerHeadLast30mRequest { + // Filter by head_slot - The head slot reported by peers (PRIMARY KEY - required) + UInt32Filter head_slot = 1 [(google.api.field_behavior) = REQUIRED, (clickhouse.v1.required_group) = "primary_key"]; + + // Filter by head_root - The head block root reported by peers (unknown if not available) (ORDER BY column 2 - optional) + StringFilter head_root = 2 [(google.api.field_behavior) = OPTIONAL]; + + // Filter by updated_date_time - Timestamp when the record was last updated (optional) + UInt32Filter updated_date_time = 3 [(google.api.field_behavior) = OPTIONAL]; + // Filter by peer_count - Total number of peers at this head (optional) + UInt32Filter peer_count = 4 [(google.api.field_behavior) = OPTIONAL]; + // Filter by count_by_client - Peer count breakdown by client implementation (optional) + MapStringUInt32Filter count_by_client = 5 [(google.api.field_behavior) = OPTIONAL]; + // Filter by count_by_country - Peer count breakdown by country (optional) + MapStringUInt32Filter count_by_country = 6 [(google.api.field_behavior) = OPTIONAL]; + // Filter by count_by_continent - Peer count breakdown by continent code (optional) + MapStringUInt32Filter count_by_continent = 7 [(google.api.field_behavior) = OPTIONAL]; + // Filter by count_by_fork_digest - Peer count breakdown by fork digest (optional) + MapStringUInt32Filter count_by_fork_digest = 8 [(google.api.field_behavior) = OPTIONAL]; + // Filter by count_by_platform - Peer count breakdown by platform (os) (optional) + MapStringUInt32Filter count_by_platform = 9 [(google.api.field_behavior) = OPTIONAL]; + // Filter by count_by_finalized_epoch - Peer count breakdown by finalized epoch (optional) + MapStringUInt32Filter count_by_finalized_epoch = 10 [(google.api.field_behavior) = OPTIONAL]; + + // The maximum number of fct_peer_head_last_30m to return. + // If unspecified, at most 100 items will be returned. + // The maximum value is 10000; values above 10000 will be coerced to 10000. + int32 page_size = 11 [(google.api.field_behavior) = OPTIONAL]; + // A page token, received from a previous `ListFctPeerHeadLast30m` call. + // Provide this to retrieve the subsequent page. + string page_token = 12 [(google.api.field_behavior) = OPTIONAL]; + // 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. + string order_by = 13 [(google.api.field_behavior) = OPTIONAL]; +} + +// Response for listing fct_peer_head_last_30m records +message ListFctPeerHeadLast30mResponse { + // The list of fct_peer_head_last_30m. + repeated FctPeerHeadLast30m fct_peer_head_last_30m = 1; + // A token, which can be sent as `page_token` to retrieve the next page. + // If this field is omitted, there are no subsequent pages. + string next_page_token = 2; +} + +// Request for getting a single fct_peer_head_last_30m record by primary key +message GetFctPeerHeadLast30mRequest { + // The head slot reported by peers + uint32 head_slot = 1; // Primary key (required) +} + +// Response for getting a single fct_peer_head_last_30m record +message GetFctPeerHeadLast30mResponse { + FctPeerHeadLast30m item = 1; +} + +// Query fct_peer_head_last_30m data +service FctPeerHeadLast30mService { + // List records | Retrieve paginated results with optional filtering + rpc List(ListFctPeerHeadLast30mRequest) returns (ListFctPeerHeadLast30mResponse) { + option (google.api.http) = { + get: "/api/v1/fct_peer_head_last_30m" + }; + } + // Get record | Retrieve a single record by head_slot + rpc Get(GetFctPeerHeadLast30mRequest) returns (GetFctPeerHeadLast30mResponse) { + option (google.api.http) = { + get: "/api/v1/fct_peer_head_last_30m/{head_slot}" + }; + } +} diff --git a/pkg/proto/clickhouse/int_peer_head.go b/pkg/proto/clickhouse/int_peer_head.go new file mode 100644 index 00000000..5f78edcf --- /dev/null +++ b/pkg/proto/clickhouse/int_peer_head.go @@ -0,0 +1,490 @@ +// Code generated by clickhouse-proto-gen. DO NOT EDIT. +// SQL query builder for int_peer_head + +package clickhouse + +import ( + "fmt" +) + +// BuildListIntPeerHeadQuery constructs a parameterized SQL query from a ListIntPeerHeadRequest +func BuildListIntPeerHeadQuery(req *ListIntPeerHeadRequest, options ...QueryOption) (SQLQuery, error) { + // Validate that at least one primary key is provided + // Primary keys can come from base table or projections + if req.HeadSlot == nil { + return SQLQuery{}, fmt.Errorf("primary key field head_slot is required") + } + + // Build query using QueryBuilder + qb := NewQueryBuilder() + + // Add primary key filter + switch filter := req.HeadSlot.Filter.(type) { + case *UInt32Filter_Eq: + qb.AddCondition("head_slot", "=", filter.Eq) + case *UInt32Filter_Ne: + qb.AddCondition("head_slot", "!=", filter.Ne) + case *UInt32Filter_Lt: + qb.AddCondition("head_slot", "<", filter.Lt) + case *UInt32Filter_Lte: + qb.AddCondition("head_slot", "<=", filter.Lte) + case *UInt32Filter_Gt: + qb.AddCondition("head_slot", ">", filter.Gt) + case *UInt32Filter_Gte: + qb.AddCondition("head_slot", ">=", filter.Gte) + case *UInt32Filter_Between: + qb.AddBetweenCondition("head_slot", filter.Between.Min, filter.Between.Max.GetValue()) + case *UInt32Filter_In: + if len(filter.In.Values) > 0 { + qb.AddInCondition("head_slot", UInt32SliceToInterface(filter.In.Values)) + } + case *UInt32Filter_NotIn: + if len(filter.NotIn.Values) > 0 { + qb.AddNotInCondition("head_slot", UInt32SliceToInterface(filter.NotIn.Values)) + } + default: + // Unsupported filter type + } + + // Add filter for column: updated_date_time + if req.UpdatedDateTime != nil { + switch filter := req.UpdatedDateTime.Filter.(type) { + case *UInt32Filter_Eq: + qb.AddCondition("updated_date_time", "=", DateTimeValue{filter.Eq}) + case *UInt32Filter_Ne: + qb.AddCondition("updated_date_time", "!=", DateTimeValue{filter.Ne}) + case *UInt32Filter_Lt: + qb.AddCondition("updated_date_time", "<", DateTimeValue{filter.Lt}) + case *UInt32Filter_Lte: + qb.AddCondition("updated_date_time", "<=", DateTimeValue{filter.Lte}) + case *UInt32Filter_Gt: + qb.AddCondition("updated_date_time", ">", DateTimeValue{filter.Gt}) + case *UInt32Filter_Gte: + qb.AddCondition("updated_date_time", ">=", DateTimeValue{filter.Gte}) + case *UInt32Filter_Between: + qb.AddBetweenCondition("updated_date_time", DateTimeValue{filter.Between.Min}, DateTimeValue{filter.Between.Max.GetValue()}) + case *UInt32Filter_In: + if len(filter.In.Values) > 0 { + converted := make([]interface{}, len(filter.In.Values)) + for i, v := range filter.In.Values { + converted[i] = DateTimeValue{v} + } + qb.AddInCondition("updated_date_time", converted) + } + case *UInt32Filter_NotIn: + if len(filter.NotIn.Values) > 0 { + converted := make([]interface{}, len(filter.NotIn.Values)) + for i, v := range filter.NotIn.Values { + converted[i] = DateTimeValue{v} + } + qb.AddNotInCondition("updated_date_time", converted) + } + default: + // Unsupported filter type + } + } + + // Add filter for column: event_date_time + if req.EventDateTime != nil { + switch filter := req.EventDateTime.Filter.(type) { + case *UInt32Filter_Eq: + qb.AddCondition("event_date_time", "=", DateTimeValue{filter.Eq}) + case *UInt32Filter_Ne: + qb.AddCondition("event_date_time", "!=", DateTimeValue{filter.Ne}) + case *UInt32Filter_Lt: + qb.AddCondition("event_date_time", "<", DateTimeValue{filter.Lt}) + case *UInt32Filter_Lte: + qb.AddCondition("event_date_time", "<=", DateTimeValue{filter.Lte}) + case *UInt32Filter_Gt: + qb.AddCondition("event_date_time", ">", DateTimeValue{filter.Gt}) + case *UInt32Filter_Gte: + qb.AddCondition("event_date_time", ">=", DateTimeValue{filter.Gte}) + case *UInt32Filter_Between: + qb.AddBetweenCondition("event_date_time", DateTimeValue{filter.Between.Min}, DateTimeValue{filter.Between.Max.GetValue()}) + case *UInt32Filter_In: + if len(filter.In.Values) > 0 { + converted := make([]interface{}, len(filter.In.Values)) + for i, v := range filter.In.Values { + converted[i] = DateTimeValue{v} + } + qb.AddInCondition("event_date_time", converted) + } + case *UInt32Filter_NotIn: + if len(filter.NotIn.Values) > 0 { + converted := make([]interface{}, len(filter.NotIn.Values)) + for i, v := range filter.NotIn.Values { + converted[i] = DateTimeValue{v} + } + qb.AddNotInCondition("event_date_time", converted) + } + default: + // Unsupported filter type + } + } + + // Add filter for column: peer_id_unique_key + if req.PeerIdUniqueKey != nil { + switch filter := req.PeerIdUniqueKey.Filter.(type) { + case *StringFilter_Eq: + qb.AddCondition("peer_id_unique_key", "=", filter.Eq) + case *StringFilter_Ne: + qb.AddCondition("peer_id_unique_key", "!=", filter.Ne) + case *StringFilter_Contains: + qb.AddLikeCondition("peer_id_unique_key", "%" + filter.Contains + "%") + case *StringFilter_StartsWith: + qb.AddLikeCondition("peer_id_unique_key", filter.StartsWith + "%") + case *StringFilter_EndsWith: + qb.AddLikeCondition("peer_id_unique_key", "%" + filter.EndsWith) + case *StringFilter_Like: + qb.AddLikeCondition("peer_id_unique_key", filter.Like) + case *StringFilter_NotLike: + qb.AddNotLikeCondition("peer_id_unique_key", filter.NotLike) + case *StringFilter_In: + if len(filter.In.Values) > 0 { + qb.AddInCondition("peer_id_unique_key", StringSliceToInterface(filter.In.Values)) + } + case *StringFilter_NotIn: + if len(filter.NotIn.Values) > 0 { + qb.AddNotInCondition("peer_id_unique_key", StringSliceToInterface(filter.NotIn.Values)) + } + default: + // Unsupported filter type + } + } + + // Add filter for column: head_root + if req.HeadRoot != nil { + switch filter := req.HeadRoot.Filter.(type) { + case *StringFilter_Eq: + qb.AddCondition("head_root", "=", filter.Eq) + case *StringFilter_Ne: + qb.AddCondition("head_root", "!=", filter.Ne) + case *StringFilter_Contains: + qb.AddLikeCondition("head_root", "%" + filter.Contains + "%") + case *StringFilter_StartsWith: + qb.AddLikeCondition("head_root", filter.StartsWith + "%") + case *StringFilter_EndsWith: + qb.AddLikeCondition("head_root", "%" + filter.EndsWith) + case *StringFilter_Like: + qb.AddLikeCondition("head_root", filter.Like) + case *StringFilter_NotLike: + qb.AddNotLikeCondition("head_root", filter.NotLike) + case *StringFilter_In: + if len(filter.In.Values) > 0 { + qb.AddInCondition("head_root", StringSliceToInterface(filter.In.Values)) + } + case *StringFilter_NotIn: + if len(filter.NotIn.Values) > 0 { + qb.AddNotInCondition("head_root", StringSliceToInterface(filter.NotIn.Values)) + } + default: + // Unsupported filter type + } + } + + // Add filter for column: fork_digest + if req.ForkDigest != nil { + switch filter := req.ForkDigest.Filter.(type) { + case *StringFilter_Eq: + qb.AddCondition("fork_digest", "=", filter.Eq) + case *StringFilter_Ne: + qb.AddCondition("fork_digest", "!=", filter.Ne) + case *StringFilter_Contains: + qb.AddLikeCondition("fork_digest", "%" + filter.Contains + "%") + case *StringFilter_StartsWith: + qb.AddLikeCondition("fork_digest", filter.StartsWith + "%") + case *StringFilter_EndsWith: + qb.AddLikeCondition("fork_digest", "%" + filter.EndsWith) + case *StringFilter_Like: + qb.AddLikeCondition("fork_digest", filter.Like) + case *StringFilter_NotLike: + qb.AddNotLikeCondition("fork_digest", filter.NotLike) + case *StringFilter_In: + if len(filter.In.Values) > 0 { + qb.AddInCondition("fork_digest", StringSliceToInterface(filter.In.Values)) + } + case *StringFilter_NotIn: + if len(filter.NotIn.Values) > 0 { + qb.AddNotInCondition("fork_digest", StringSliceToInterface(filter.NotIn.Values)) + } + default: + // Unsupported filter type + } + } + + // Add filter for column: finalized_epoch + if req.FinalizedEpoch != nil { + switch filter := req.FinalizedEpoch.Filter.(type) { + case *NullableUInt32Filter_Eq: + qb.AddCondition("finalized_epoch", "=", filter.Eq) + case *NullableUInt32Filter_Ne: + qb.AddCondition("finalized_epoch", "!=", filter.Ne) + case *NullableUInt32Filter_Lt: + qb.AddCondition("finalized_epoch", "<", filter.Lt) + case *NullableUInt32Filter_Lte: + qb.AddCondition("finalized_epoch", "<=", filter.Lte) + case *NullableUInt32Filter_Gt: + qb.AddCondition("finalized_epoch", ">", filter.Gt) + case *NullableUInt32Filter_Gte: + qb.AddCondition("finalized_epoch", ">=", filter.Gte) + case *NullableUInt32Filter_Between: + qb.AddBetweenCondition("finalized_epoch", filter.Between.Min, filter.Between.Max.GetValue()) + case *NullableUInt32Filter_In: + if len(filter.In.Values) > 0 { + qb.AddInCondition("finalized_epoch", UInt32SliceToInterface(filter.In.Values)) + } + case *NullableUInt32Filter_NotIn: + if len(filter.NotIn.Values) > 0 { + qb.AddNotInCondition("finalized_epoch", UInt32SliceToInterface(filter.NotIn.Values)) + } + case *NullableUInt32Filter_IsNull: + qb.AddIsNullCondition("finalized_epoch") + case *NullableUInt32Filter_IsNotNull: + qb.AddIsNotNullCondition("finalized_epoch") + default: + // Unsupported filter type + } + } + + // Add filter for column: client + if req.Client != nil { + switch filter := req.Client.Filter.(type) { + case *StringFilter_Eq: + qb.AddCondition("client", "=", filter.Eq) + case *StringFilter_Ne: + qb.AddCondition("client", "!=", filter.Ne) + case *StringFilter_Contains: + qb.AddLikeCondition("client", "%" + filter.Contains + "%") + case *StringFilter_StartsWith: + qb.AddLikeCondition("client", filter.StartsWith + "%") + case *StringFilter_EndsWith: + qb.AddLikeCondition("client", "%" + filter.EndsWith) + case *StringFilter_Like: + qb.AddLikeCondition("client", filter.Like) + case *StringFilter_NotLike: + qb.AddNotLikeCondition("client", filter.NotLike) + case *StringFilter_In: + if len(filter.In.Values) > 0 { + qb.AddInCondition("client", StringSliceToInterface(filter.In.Values)) + } + case *StringFilter_NotIn: + if len(filter.NotIn.Values) > 0 { + qb.AddNotInCondition("client", StringSliceToInterface(filter.NotIn.Values)) + } + default: + // Unsupported filter type + } + } + + // Add filter for column: client_version + if req.ClientVersion != nil { + switch filter := req.ClientVersion.Filter.(type) { + case *StringFilter_Eq: + qb.AddCondition("client_version", "=", filter.Eq) + case *StringFilter_Ne: + qb.AddCondition("client_version", "!=", filter.Ne) + case *StringFilter_Contains: + qb.AddLikeCondition("client_version", "%" + filter.Contains + "%") + case *StringFilter_StartsWith: + qb.AddLikeCondition("client_version", filter.StartsWith + "%") + case *StringFilter_EndsWith: + qb.AddLikeCondition("client_version", "%" + filter.EndsWith) + case *StringFilter_Like: + qb.AddLikeCondition("client_version", filter.Like) + case *StringFilter_NotLike: + qb.AddNotLikeCondition("client_version", filter.NotLike) + case *StringFilter_In: + if len(filter.In.Values) > 0 { + qb.AddInCondition("client_version", StringSliceToInterface(filter.In.Values)) + } + case *StringFilter_NotIn: + if len(filter.NotIn.Values) > 0 { + qb.AddNotInCondition("client_version", StringSliceToInterface(filter.NotIn.Values)) + } + default: + // Unsupported filter type + } + } + + // Add filter for column: platform + if req.Platform != nil { + switch filter := req.Platform.Filter.(type) { + case *StringFilter_Eq: + qb.AddCondition("platform", "=", filter.Eq) + case *StringFilter_Ne: + qb.AddCondition("platform", "!=", filter.Ne) + case *StringFilter_Contains: + qb.AddLikeCondition("platform", "%" + filter.Contains + "%") + case *StringFilter_StartsWith: + qb.AddLikeCondition("platform", filter.StartsWith + "%") + case *StringFilter_EndsWith: + qb.AddLikeCondition("platform", "%" + filter.EndsWith) + case *StringFilter_Like: + qb.AddLikeCondition("platform", filter.Like) + case *StringFilter_NotLike: + qb.AddNotLikeCondition("platform", filter.NotLike) + case *StringFilter_In: + if len(filter.In.Values) > 0 { + qb.AddInCondition("platform", StringSliceToInterface(filter.In.Values)) + } + case *StringFilter_NotIn: + if len(filter.NotIn.Values) > 0 { + qb.AddNotInCondition("platform", StringSliceToInterface(filter.NotIn.Values)) + } + default: + // Unsupported filter type + } + } + + // Add filter for column: country + if req.Country != nil { + switch filter := req.Country.Filter.(type) { + case *StringFilter_Eq: + qb.AddCondition("country", "=", filter.Eq) + case *StringFilter_Ne: + qb.AddCondition("country", "!=", filter.Ne) + case *StringFilter_Contains: + qb.AddLikeCondition("country", "%" + filter.Contains + "%") + case *StringFilter_StartsWith: + qb.AddLikeCondition("country", filter.StartsWith + "%") + case *StringFilter_EndsWith: + qb.AddLikeCondition("country", "%" + filter.EndsWith) + case *StringFilter_Like: + qb.AddLikeCondition("country", filter.Like) + case *StringFilter_NotLike: + qb.AddNotLikeCondition("country", filter.NotLike) + case *StringFilter_In: + if len(filter.In.Values) > 0 { + qb.AddInCondition("country", StringSliceToInterface(filter.In.Values)) + } + case *StringFilter_NotIn: + if len(filter.NotIn.Values) > 0 { + qb.AddNotInCondition("country", StringSliceToInterface(filter.NotIn.Values)) + } + default: + // Unsupported filter type + } + } + + // Add filter for column: country_code + if req.CountryCode != nil { + switch filter := req.CountryCode.Filter.(type) { + case *StringFilter_Eq: + qb.AddCondition("country_code", "=", filter.Eq) + case *StringFilter_Ne: + qb.AddCondition("country_code", "!=", filter.Ne) + case *StringFilter_Contains: + qb.AddLikeCondition("country_code", "%" + filter.Contains + "%") + case *StringFilter_StartsWith: + qb.AddLikeCondition("country_code", filter.StartsWith + "%") + case *StringFilter_EndsWith: + qb.AddLikeCondition("country_code", "%" + filter.EndsWith) + case *StringFilter_Like: + qb.AddLikeCondition("country_code", filter.Like) + case *StringFilter_NotLike: + qb.AddNotLikeCondition("country_code", filter.NotLike) + case *StringFilter_In: + if len(filter.In.Values) > 0 { + qb.AddInCondition("country_code", StringSliceToInterface(filter.In.Values)) + } + case *StringFilter_NotIn: + if len(filter.NotIn.Values) > 0 { + qb.AddNotInCondition("country_code", StringSliceToInterface(filter.NotIn.Values)) + } + default: + // Unsupported filter type + } + } + + // Add filter for column: continent_code + if req.ContinentCode != nil { + switch filter := req.ContinentCode.Filter.(type) { + case *StringFilter_Eq: + qb.AddCondition("continent_code", "=", filter.Eq) + case *StringFilter_Ne: + qb.AddCondition("continent_code", "!=", filter.Ne) + case *StringFilter_Contains: + qb.AddLikeCondition("continent_code", "%" + filter.Contains + "%") + case *StringFilter_StartsWith: + qb.AddLikeCondition("continent_code", filter.StartsWith + "%") + case *StringFilter_EndsWith: + qb.AddLikeCondition("continent_code", "%" + filter.EndsWith) + case *StringFilter_Like: + qb.AddLikeCondition("continent_code", filter.Like) + case *StringFilter_NotLike: + qb.AddNotLikeCondition("continent_code", filter.NotLike) + case *StringFilter_In: + if len(filter.In.Values) > 0 { + qb.AddInCondition("continent_code", StringSliceToInterface(filter.In.Values)) + } + case *StringFilter_NotIn: + if len(filter.NotIn.Values) > 0 { + qb.AddNotInCondition("continent_code", StringSliceToInterface(filter.NotIn.Values)) + } + default: + // Unsupported filter type + } + } + + // Handle pagination per AIP-132 + // Validate page size + if req.PageSize < 0 { + return SQLQuery{}, fmt.Errorf("page_size must be non-negative, got %d", req.PageSize) + } + if req.PageSize > 10000 { + return SQLQuery{}, fmt.Errorf("page_size must not exceed %d, got %d", 10000, req.PageSize) + } + + var limit, offset uint32 + limit = 100 // Default page size + if req.PageSize > 0 { + limit = uint32(req.PageSize) + } + if req.PageToken != "" { + decodedOffset, err := DecodePageToken(req.PageToken) + if err != nil { + return SQLQuery{}, fmt.Errorf("invalid page_token: %w", err) + } + offset = decodedOffset + } + + // Handle custom ordering if provided + var orderByClause string + if req.OrderBy != "" { + validFields := []string{"updated_date_time", "event_date_time", "peer_id_unique_key", "head_slot", "head_root", "fork_digest", "finalized_epoch", "client", "client_version", "platform", "country", "country_code", "continent_code"} + orderFields, err := ParseOrderBy(req.OrderBy, validFields) + if err != nil { + return SQLQuery{}, fmt.Errorf("invalid order_by: %w", err) + } + orderByClause = BuildOrderByClause(orderFields) + } else { + // Default sorting by primary key + orderByClause = " ORDER BY head_slot" + ", peer_id_unique_key" + } + + // Build column list + columns := []string{"toUnixTimestamp(`updated_date_time`) AS `updated_date_time`", "toUnixTimestamp(`event_date_time`) AS `event_date_time`", "peer_id_unique_key", "head_slot", "head_root", "fork_digest", "finalized_epoch", "client", "client_version", "platform", "country", "country_code", "continent_code"} + + return BuildParameterizedQuery("int_peer_head", columns, qb, orderByClause, limit, offset, options...) +} + +// BuildGetIntPeerHeadQuery constructs a parameterized SQL query from a GetIntPeerHeadRequest +func BuildGetIntPeerHeadQuery(req *GetIntPeerHeadRequest, options ...QueryOption) (SQLQuery, error) { + // Validate primary key is provided + if req.HeadSlot == 0 { + return SQLQuery{}, fmt.Errorf("primary key field head_slot is required") + } + + // Build query with primary key condition + qb := NewQueryBuilder() + qb.AddCondition("head_slot", "=", req.HeadSlot) + + // Build ORDER BY clause + orderByClause := " ORDER BY head_slot, peer_id_unique_key" + + // Build column list + columns := []string{"toUnixTimestamp(`updated_date_time`) AS `updated_date_time`", "toUnixTimestamp(`event_date_time`) AS `event_date_time`", "peer_id_unique_key", "head_slot", "head_root", "fork_digest", "finalized_epoch", "client", "client_version", "platform", "country", "country_code", "continent_code"} + + // Return single record + return BuildParameterizedQuery("int_peer_head", columns, qb, orderByClause, 1, 0, options...) +} diff --git a/pkg/proto/clickhouse/int_peer_head.pb.go b/pkg/proto/clickhouse/int_peer_head.pb.go new file mode 100644 index 00000000..587260e9 --- /dev/null +++ b/pkg/proto/clickhouse/int_peer_head.pb.go @@ -0,0 +1,784 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.34.2 +// protoc (unknown) +// source: int_peer_head.proto + +package clickhouse + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + wrapperspb "google.golang.org/protobuf/types/known/wrapperspb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type IntPeerHead struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Timestamp when the record was last updated + UpdatedDateTime uint32 `protobuf:"varint,11,opt,name=updated_date_time,json=updatedDateTime,proto3" json:"updated_date_time,omitempty"` + // Timestamp when the status was observed + EventDateTime uint32 `protobuf:"varint,12,opt,name=event_date_time,json=eventDateTime,proto3" json:"event_date_time,omitempty"` + // Unique key for the peer + PeerIdUniqueKey string `protobuf:"bytes,13,opt,name=peer_id_unique_key,json=peerIdUniqueKey,proto3" json:"peer_id_unique_key,omitempty"` + // The head slot reported by the peer + HeadSlot uint32 `protobuf:"varint,14,opt,name=head_slot,json=headSlot,proto3" json:"head_slot,omitempty"` + // The head block root reported by the peer + HeadRoot string `protobuf:"bytes,15,opt,name=head_root,json=headRoot,proto3" json:"head_root,omitempty"` + // The fork digest reported by the peer + ForkDigest string `protobuf:"bytes,16,opt,name=fork_digest,json=forkDigest,proto3" json:"fork_digest,omitempty"` + // The finalized epoch reported by the peer + FinalizedEpoch *wrapperspb.UInt32Value `protobuf:"bytes,17,opt,name=finalized_epoch,json=finalizedEpoch,proto3" json:"finalized_epoch,omitempty"` + // Client implementation (e.g., lighthouse, prysm) + Client string `protobuf:"bytes,18,opt,name=client,proto3" json:"client,omitempty"` + // Client version + ClientVersion string `protobuf:"bytes,19,opt,name=client_version,json=clientVersion,proto3" json:"client_version,omitempty"` + // Platform/OS + Platform string `protobuf:"bytes,20,opt,name=platform,proto3" json:"platform,omitempty"` + // Country name + Country string `protobuf:"bytes,21,opt,name=country,proto3" json:"country,omitempty"` + // Country code + CountryCode string `protobuf:"bytes,22,opt,name=country_code,json=countryCode,proto3" json:"country_code,omitempty"` + // Continent code + ContinentCode string `protobuf:"bytes,23,opt,name=continent_code,json=continentCode,proto3" json:"continent_code,omitempty"` +} + +func (x *IntPeerHead) Reset() { + *x = IntPeerHead{} + if protoimpl.UnsafeEnabled { + mi := &file_int_peer_head_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IntPeerHead) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IntPeerHead) ProtoMessage() {} + +func (x *IntPeerHead) ProtoReflect() protoreflect.Message { + mi := &file_int_peer_head_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IntPeerHead.ProtoReflect.Descriptor instead. +func (*IntPeerHead) Descriptor() ([]byte, []int) { + return file_int_peer_head_proto_rawDescGZIP(), []int{0} +} + +func (x *IntPeerHead) GetUpdatedDateTime() uint32 { + if x != nil { + return x.UpdatedDateTime + } + return 0 +} + +func (x *IntPeerHead) GetEventDateTime() uint32 { + if x != nil { + return x.EventDateTime + } + return 0 +} + +func (x *IntPeerHead) GetPeerIdUniqueKey() string { + if x != nil { + return x.PeerIdUniqueKey + } + return "" +} + +func (x *IntPeerHead) GetHeadSlot() uint32 { + if x != nil { + return x.HeadSlot + } + return 0 +} + +func (x *IntPeerHead) GetHeadRoot() string { + if x != nil { + return x.HeadRoot + } + return "" +} + +func (x *IntPeerHead) GetForkDigest() string { + if x != nil { + return x.ForkDigest + } + return "" +} + +func (x *IntPeerHead) GetFinalizedEpoch() *wrapperspb.UInt32Value { + if x != nil { + return x.FinalizedEpoch + } + return nil +} + +func (x *IntPeerHead) GetClient() string { + if x != nil { + return x.Client + } + return "" +} + +func (x *IntPeerHead) GetClientVersion() string { + if x != nil { + return x.ClientVersion + } + return "" +} + +func (x *IntPeerHead) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + +func (x *IntPeerHead) GetCountry() string { + if x != nil { + return x.Country + } + return "" +} + +func (x *IntPeerHead) GetCountryCode() string { + if x != nil { + return x.CountryCode + } + return "" +} + +func (x *IntPeerHead) GetContinentCode() string { + if x != nil { + return x.ContinentCode + } + return "" +} + +// Request for listing int_peer_head records +type ListIntPeerHeadRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Filter by head_slot - The head slot reported by the peer (PRIMARY KEY - required) + HeadSlot *UInt32Filter `protobuf:"bytes,1,opt,name=head_slot,json=headSlot,proto3" json:"head_slot,omitempty"` + // Filter by peer_id_unique_key - Unique key for the peer (ORDER BY column 2 - optional) + PeerIdUniqueKey *StringFilter `protobuf:"bytes,2,opt,name=peer_id_unique_key,json=peerIdUniqueKey,proto3" json:"peer_id_unique_key,omitempty"` + // Filter by updated_date_time - Timestamp when the record was last updated (optional) + UpdatedDateTime *UInt32Filter `protobuf:"bytes,3,opt,name=updated_date_time,json=updatedDateTime,proto3" json:"updated_date_time,omitempty"` + // Filter by event_date_time - Timestamp when the status was observed (optional) + EventDateTime *UInt32Filter `protobuf:"bytes,4,opt,name=event_date_time,json=eventDateTime,proto3" json:"event_date_time,omitempty"` + // Filter by head_root - The head block root reported by the peer (optional) + HeadRoot *StringFilter `protobuf:"bytes,5,opt,name=head_root,json=headRoot,proto3" json:"head_root,omitempty"` + // Filter by fork_digest - The fork digest reported by the peer (optional) + ForkDigest *StringFilter `protobuf:"bytes,6,opt,name=fork_digest,json=forkDigest,proto3" json:"fork_digest,omitempty"` + // Filter by finalized_epoch - The finalized epoch reported by the peer (optional) + FinalizedEpoch *NullableUInt32Filter `protobuf:"bytes,7,opt,name=finalized_epoch,json=finalizedEpoch,proto3" json:"finalized_epoch,omitempty"` + // Filter by client - Client implementation (e.g., lighthouse, prysm) (optional) + Client *StringFilter `protobuf:"bytes,8,opt,name=client,proto3" json:"client,omitempty"` + // Filter by client_version - Client version (optional) + ClientVersion *StringFilter `protobuf:"bytes,9,opt,name=client_version,json=clientVersion,proto3" json:"client_version,omitempty"` + // Filter by platform - Platform/OS (optional) + Platform *StringFilter `protobuf:"bytes,10,opt,name=platform,proto3" json:"platform,omitempty"` + // Filter by country - Country name (optional) + Country *StringFilter `protobuf:"bytes,11,opt,name=country,proto3" json:"country,omitempty"` + // Filter by country_code - Country code (optional) + CountryCode *StringFilter `protobuf:"bytes,12,opt,name=country_code,json=countryCode,proto3" json:"country_code,omitempty"` + // Filter by continent_code - Continent code (optional) + ContinentCode *StringFilter `protobuf:"bytes,13,opt,name=continent_code,json=continentCode,proto3" json:"continent_code,omitempty"` + // The maximum number of int_peer_head to return. + // If unspecified, at most 100 items will be returned. + // The maximum value is 10000; values above 10000 will be coerced to 10000. + PageSize int32 `protobuf:"varint,14,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + // A page token, received from a previous `ListIntPeerHead` call. + // Provide this to retrieve the subsequent page. + PageToken string `protobuf:"bytes,15,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"` + // 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. + OrderBy string `protobuf:"bytes,16,opt,name=order_by,json=orderBy,proto3" json:"order_by,omitempty"` +} + +func (x *ListIntPeerHeadRequest) Reset() { + *x = ListIntPeerHeadRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_int_peer_head_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListIntPeerHeadRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListIntPeerHeadRequest) ProtoMessage() {} + +func (x *ListIntPeerHeadRequest) ProtoReflect() protoreflect.Message { + mi := &file_int_peer_head_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListIntPeerHeadRequest.ProtoReflect.Descriptor instead. +func (*ListIntPeerHeadRequest) Descriptor() ([]byte, []int) { + return file_int_peer_head_proto_rawDescGZIP(), []int{1} +} + +func (x *ListIntPeerHeadRequest) GetHeadSlot() *UInt32Filter { + if x != nil { + return x.HeadSlot + } + return nil +} + +func (x *ListIntPeerHeadRequest) GetPeerIdUniqueKey() *StringFilter { + if x != nil { + return x.PeerIdUniqueKey + } + return nil +} + +func (x *ListIntPeerHeadRequest) GetUpdatedDateTime() *UInt32Filter { + if x != nil { + return x.UpdatedDateTime + } + return nil +} + +func (x *ListIntPeerHeadRequest) GetEventDateTime() *UInt32Filter { + if x != nil { + return x.EventDateTime + } + return nil +} + +func (x *ListIntPeerHeadRequest) GetHeadRoot() *StringFilter { + if x != nil { + return x.HeadRoot + } + return nil +} + +func (x *ListIntPeerHeadRequest) GetForkDigest() *StringFilter { + if x != nil { + return x.ForkDigest + } + return nil +} + +func (x *ListIntPeerHeadRequest) GetFinalizedEpoch() *NullableUInt32Filter { + if x != nil { + return x.FinalizedEpoch + } + return nil +} + +func (x *ListIntPeerHeadRequest) GetClient() *StringFilter { + if x != nil { + return x.Client + } + return nil +} + +func (x *ListIntPeerHeadRequest) GetClientVersion() *StringFilter { + if x != nil { + return x.ClientVersion + } + return nil +} + +func (x *ListIntPeerHeadRequest) GetPlatform() *StringFilter { + if x != nil { + return x.Platform + } + return nil +} + +func (x *ListIntPeerHeadRequest) GetCountry() *StringFilter { + if x != nil { + return x.Country + } + return nil +} + +func (x *ListIntPeerHeadRequest) GetCountryCode() *StringFilter { + if x != nil { + return x.CountryCode + } + return nil +} + +func (x *ListIntPeerHeadRequest) GetContinentCode() *StringFilter { + if x != nil { + return x.ContinentCode + } + return nil +} + +func (x *ListIntPeerHeadRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *ListIntPeerHeadRequest) GetPageToken() string { + if x != nil { + return x.PageToken + } + return "" +} + +func (x *ListIntPeerHeadRequest) GetOrderBy() string { + if x != nil { + return x.OrderBy + } + return "" +} + +// Response for listing int_peer_head records +type ListIntPeerHeadResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The list of int_peer_head. + IntPeerHead []*IntPeerHead `protobuf:"bytes,1,rep,name=int_peer_head,json=intPeerHead,proto3" json:"int_peer_head,omitempty"` + // A token, which can be sent as `page_token` to retrieve the next page. + // If this field is omitted, there are no subsequent pages. + NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` +} + +func (x *ListIntPeerHeadResponse) Reset() { + *x = ListIntPeerHeadResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_int_peer_head_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListIntPeerHeadResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListIntPeerHeadResponse) ProtoMessage() {} + +func (x *ListIntPeerHeadResponse) ProtoReflect() protoreflect.Message { + mi := &file_int_peer_head_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListIntPeerHeadResponse.ProtoReflect.Descriptor instead. +func (*ListIntPeerHeadResponse) Descriptor() ([]byte, []int) { + return file_int_peer_head_proto_rawDescGZIP(), []int{2} +} + +func (x *ListIntPeerHeadResponse) GetIntPeerHead() []*IntPeerHead { + if x != nil { + return x.IntPeerHead + } + return nil +} + +func (x *ListIntPeerHeadResponse) GetNextPageToken() string { + if x != nil { + return x.NextPageToken + } + return "" +} + +// Request for getting a single int_peer_head record by primary key +type GetIntPeerHeadRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The head slot reported by the peer + HeadSlot uint32 `protobuf:"varint,1,opt,name=head_slot,json=headSlot,proto3" json:"head_slot,omitempty"` // Primary key (required) +} + +func (x *GetIntPeerHeadRequest) Reset() { + *x = GetIntPeerHeadRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_int_peer_head_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetIntPeerHeadRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetIntPeerHeadRequest) ProtoMessage() {} + +func (x *GetIntPeerHeadRequest) ProtoReflect() protoreflect.Message { + mi := &file_int_peer_head_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetIntPeerHeadRequest.ProtoReflect.Descriptor instead. +func (*GetIntPeerHeadRequest) Descriptor() ([]byte, []int) { + return file_int_peer_head_proto_rawDescGZIP(), []int{3} +} + +func (x *GetIntPeerHeadRequest) GetHeadSlot() uint32 { + if x != nil { + return x.HeadSlot + } + return 0 +} + +// Response for getting a single int_peer_head record +type GetIntPeerHeadResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Item *IntPeerHead `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` +} + +func (x *GetIntPeerHeadResponse) Reset() { + *x = GetIntPeerHeadResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_int_peer_head_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetIntPeerHeadResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetIntPeerHeadResponse) ProtoMessage() {} + +func (x *GetIntPeerHeadResponse) ProtoReflect() protoreflect.Message { + mi := &file_int_peer_head_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetIntPeerHeadResponse.ProtoReflect.Descriptor instead. +func (*GetIntPeerHeadResponse) Descriptor() ([]byte, []int) { + return file_int_peer_head_proto_rawDescGZIP(), []int{4} +} + +func (x *GetIntPeerHeadResponse) GetItem() *IntPeerHead { + if x != nil { + return x.Item + } + return nil +} + +var File_int_peer_head_proto protoreflect.FileDescriptor + +var file_int_peer_head_proto_rawDesc = []byte{ + 0x0a, 0x13, 0x69, 0x6e, 0x74, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x63, 0x62, 0x74, 0x1a, 0x0c, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, + 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xef, 0x03, 0x0a, 0x0b, 0x49, 0x6e, 0x74, + 0x50, 0x65, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0b, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, + 0x54, 0x69, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x61, + 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x12, + 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x5f, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x5f, 0x6b, + 0x65, 0x79, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, + 0x55, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x65, 0x61, + 0x64, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x68, 0x65, + 0x61, 0x64, 0x53, 0x6c, 0x6f, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x72, + 0x6f, 0x6f, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x65, 0x61, 0x64, 0x52, + 0x6f, 0x6f, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x6f, 0x72, 0x6b, 0x5f, 0x64, 0x69, 0x67, 0x65, + 0x73, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x6f, 0x72, 0x6b, 0x44, 0x69, + 0x67, 0x65, 0x73, 0x74, 0x12, 0x45, 0x0a, 0x0f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, + 0x64, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x66, 0x69, 0x6e, + 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, + 0x79, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, + 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, + 0x6f, 0x64, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x65, 0x6e, 0x74, + 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x6e, + 0x74, 0x69, 0x6e, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x22, 0xb2, 0x06, 0x0a, 0x16, 0x4c, + 0x69, 0x73, 0x74, 0x49, 0x6e, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x09, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x73, 0x6c, + 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x55, + 0x49, 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x08, 0x68, 0x65, 0x61, + 0x64, 0x53, 0x6c, 0x6f, 0x74, 0x12, 0x3e, 0x0a, 0x12, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x5f, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x46, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x52, 0x0f, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x55, 0x6e, 0x69, 0x71, + 0x75, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x3d, 0x0a, 0x11, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x11, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x52, 0x0f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, + 0x54, 0x69, 0x6d, 0x65, 0x12, 0x39, 0x0a, 0x0f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x61, + 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, + 0x63, 0x62, 0x74, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, + 0x2e, 0x0a, 0x09, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x46, + 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x08, 0x68, 0x65, 0x61, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x12, + 0x32, 0x0a, 0x0b, 0x66, 0x6f, 0x72, 0x6b, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x0a, 0x66, 0x6f, 0x72, 0x6b, 0x44, 0x69, 0x67, + 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x0f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, + 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, + 0x62, 0x74, 0x2e, 0x4e, 0x75, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x49, 0x6e, 0x74, 0x33, + 0x32, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x0e, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, + 0x65, 0x64, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x29, 0x0a, 0x06, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x53, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x06, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x0e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x62, 0x74, + 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x0d, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x08, + 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, + 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x46, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x2b, 0x0a, 0x07, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, + 0x62, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, + 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x34, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, + 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x46, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x38, + 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x64, 0x65, + 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x53, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x69, + 0x6e, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, + 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, + 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x62, 0x79, + 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x42, 0x79, 0x22, + 0x77, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, 0x65, + 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x0d, 0x69, 0x6e, + 0x74, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, + 0x65, 0x61, 0x64, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, + 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, + 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x34, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x49, + 0x6e, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x68, 0x65, 0x61, 0x64, 0x53, 0x6c, 0x6f, 0x74, 0x22, 0x3e, + 0x0a, 0x16, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x49, 0x6e, 0x74, + 0x50, 0x65, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x32, 0x97, + 0x01, 0x0a, 0x12, 0x49, 0x6e, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1b, 0x2e, + 0x63, 0x62, 0x74, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, + 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x63, 0x62, 0x74, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, + 0x1a, 0x2e, 0x63, 0x62, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x50, 0x65, 0x65, 0x72, + 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x63, 0x62, + 0x74, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x50, 0x65, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x36, 0x5a, 0x34, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x74, 0x68, 0x70, 0x61, 0x6e, 0x64, 0x61, 0x6f, + 0x70, 0x73, 0x2f, 0x78, 0x61, 0x74, 0x75, 0x2d, 0x63, 0x62, 0x74, 0x2f, 0x70, 0x6b, 0x67, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x68, 0x6f, 0x75, 0x73, 0x65, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_int_peer_head_proto_rawDescOnce sync.Once + file_int_peer_head_proto_rawDescData = file_int_peer_head_proto_rawDesc +) + +func file_int_peer_head_proto_rawDescGZIP() []byte { + file_int_peer_head_proto_rawDescOnce.Do(func() { + file_int_peer_head_proto_rawDescData = protoimpl.X.CompressGZIP(file_int_peer_head_proto_rawDescData) + }) + return file_int_peer_head_proto_rawDescData +} + +var file_int_peer_head_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_int_peer_head_proto_goTypes = []any{ + (*IntPeerHead)(nil), // 0: cbt.IntPeerHead + (*ListIntPeerHeadRequest)(nil), // 1: cbt.ListIntPeerHeadRequest + (*ListIntPeerHeadResponse)(nil), // 2: cbt.ListIntPeerHeadResponse + (*GetIntPeerHeadRequest)(nil), // 3: cbt.GetIntPeerHeadRequest + (*GetIntPeerHeadResponse)(nil), // 4: cbt.GetIntPeerHeadResponse + (*wrapperspb.UInt32Value)(nil), // 5: google.protobuf.UInt32Value + (*UInt32Filter)(nil), // 6: cbt.UInt32Filter + (*StringFilter)(nil), // 7: cbt.StringFilter + (*NullableUInt32Filter)(nil), // 8: cbt.NullableUInt32Filter +} +var file_int_peer_head_proto_depIdxs = []int32{ + 5, // 0: cbt.IntPeerHead.finalized_epoch:type_name -> google.protobuf.UInt32Value + 6, // 1: cbt.ListIntPeerHeadRequest.head_slot:type_name -> cbt.UInt32Filter + 7, // 2: cbt.ListIntPeerHeadRequest.peer_id_unique_key:type_name -> cbt.StringFilter + 6, // 3: cbt.ListIntPeerHeadRequest.updated_date_time:type_name -> cbt.UInt32Filter + 6, // 4: cbt.ListIntPeerHeadRequest.event_date_time:type_name -> cbt.UInt32Filter + 7, // 5: cbt.ListIntPeerHeadRequest.head_root:type_name -> cbt.StringFilter + 7, // 6: cbt.ListIntPeerHeadRequest.fork_digest:type_name -> cbt.StringFilter + 8, // 7: cbt.ListIntPeerHeadRequest.finalized_epoch:type_name -> cbt.NullableUInt32Filter + 7, // 8: cbt.ListIntPeerHeadRequest.client:type_name -> cbt.StringFilter + 7, // 9: cbt.ListIntPeerHeadRequest.client_version:type_name -> cbt.StringFilter + 7, // 10: cbt.ListIntPeerHeadRequest.platform:type_name -> cbt.StringFilter + 7, // 11: cbt.ListIntPeerHeadRequest.country:type_name -> cbt.StringFilter + 7, // 12: cbt.ListIntPeerHeadRequest.country_code:type_name -> cbt.StringFilter + 7, // 13: cbt.ListIntPeerHeadRequest.continent_code:type_name -> cbt.StringFilter + 0, // 14: cbt.ListIntPeerHeadResponse.int_peer_head:type_name -> cbt.IntPeerHead + 0, // 15: cbt.GetIntPeerHeadResponse.item:type_name -> cbt.IntPeerHead + 1, // 16: cbt.IntPeerHeadService.List:input_type -> cbt.ListIntPeerHeadRequest + 3, // 17: cbt.IntPeerHeadService.Get:input_type -> cbt.GetIntPeerHeadRequest + 2, // 18: cbt.IntPeerHeadService.List:output_type -> cbt.ListIntPeerHeadResponse + 4, // 19: cbt.IntPeerHeadService.Get:output_type -> cbt.GetIntPeerHeadResponse + 18, // [18:20] is the sub-list for method output_type + 16, // [16:18] is the sub-list for method input_type + 16, // [16:16] is the sub-list for extension type_name + 16, // [16:16] is the sub-list for extension extendee + 0, // [0:16] is the sub-list for field type_name +} + +func init() { file_int_peer_head_proto_init() } +func file_int_peer_head_proto_init() { + if File_int_peer_head_proto != nil { + return + } + file_common_proto_init() + if !protoimpl.UnsafeEnabled { + file_int_peer_head_proto_msgTypes[0].Exporter = func(v any, i int) any { + switch v := v.(*IntPeerHead); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_int_peer_head_proto_msgTypes[1].Exporter = func(v any, i int) any { + switch v := v.(*ListIntPeerHeadRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_int_peer_head_proto_msgTypes[2].Exporter = func(v any, i int) any { + switch v := v.(*ListIntPeerHeadResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_int_peer_head_proto_msgTypes[3].Exporter = func(v any, i int) any { + switch v := v.(*GetIntPeerHeadRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_int_peer_head_proto_msgTypes[4].Exporter = func(v any, i int) any { + switch v := v.(*GetIntPeerHeadResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_int_peer_head_proto_rawDesc, + NumEnums: 0, + NumMessages: 5, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_int_peer_head_proto_goTypes, + DependencyIndexes: file_int_peer_head_proto_depIdxs, + MessageInfos: file_int_peer_head_proto_msgTypes, + }.Build() + File_int_peer_head_proto = out.File + file_int_peer_head_proto_rawDesc = nil + file_int_peer_head_proto_goTypes = nil + file_int_peer_head_proto_depIdxs = nil +} diff --git a/pkg/proto/clickhouse/int_peer_head.proto b/pkg/proto/clickhouse/int_peer_head.proto new file mode 100644 index 00000000..be5ea40c --- /dev/null +++ b/pkg/proto/clickhouse/int_peer_head.proto @@ -0,0 +1,110 @@ +syntax = "proto3"; + +package cbt; + +import "common.proto"; +import "google/protobuf/wrappers.proto"; + +option go_package = "github.com/ethpandaops/xatu-cbt/pkg/proto/clickhouse"; +// Per-peer head observations from handle_status events, enriched with metadata + +message IntPeerHead { + // Timestamp when the record was last updated + uint32 updated_date_time = 11; + // Timestamp when the status was observed + uint32 event_date_time = 12; + // Unique key for the peer + string peer_id_unique_key = 13; + // The head slot reported by the peer + uint32 head_slot = 14; + // The head block root reported by the peer + string head_root = 15; + // The fork digest reported by the peer + string fork_digest = 16; + // The finalized epoch reported by the peer + google.protobuf.UInt32Value finalized_epoch = 17; + // Client implementation (e.g., lighthouse, prysm) + string client = 18; + // Client version + string client_version = 19; + // Platform/OS + string platform = 20; + // Country name + string country = 21; + // Country code + string country_code = 22; + // Continent code + string continent_code = 23; +} + +// Request for listing int_peer_head records +message ListIntPeerHeadRequest { + // Filter by head_slot - The head slot reported by the peer (PRIMARY KEY - required) + UInt32Filter head_slot = 1; + + // Filter by peer_id_unique_key - Unique key for the peer (ORDER BY column 2 - optional) + StringFilter peer_id_unique_key = 2; + + // Filter by updated_date_time - Timestamp when the record was last updated (optional) + UInt32Filter updated_date_time = 3; + // Filter by event_date_time - Timestamp when the status was observed (optional) + UInt32Filter event_date_time = 4; + // Filter by head_root - The head block root reported by the peer (optional) + StringFilter head_root = 5; + // Filter by fork_digest - The fork digest reported by the peer (optional) + StringFilter fork_digest = 6; + // Filter by finalized_epoch - The finalized epoch reported by the peer (optional) + NullableUInt32Filter finalized_epoch = 7; + // Filter by client - Client implementation (e.g., lighthouse, prysm) (optional) + StringFilter client = 8; + // Filter by client_version - Client version (optional) + StringFilter client_version = 9; + // Filter by platform - Platform/OS (optional) + StringFilter platform = 10; + // Filter by country - Country name (optional) + StringFilter country = 11; + // Filter by country_code - Country code (optional) + StringFilter country_code = 12; + // Filter by continent_code - Continent code (optional) + StringFilter continent_code = 13; + + // The maximum number of int_peer_head to return. + // If unspecified, at most 100 items will be returned. + // The maximum value is 10000; values above 10000 will be coerced to 10000. + int32 page_size = 14; + // A page token, received from a previous `ListIntPeerHead` call. + // Provide this to retrieve the subsequent page. + string page_token = 15; + // 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. + string order_by = 16; +} + +// Response for listing int_peer_head records +message ListIntPeerHeadResponse { + // The list of int_peer_head. + repeated IntPeerHead int_peer_head = 1; + // A token, which can be sent as `page_token` to retrieve the next page. + // If this field is omitted, there are no subsequent pages. + string next_page_token = 2; +} + +// Request for getting a single int_peer_head record by primary key +message GetIntPeerHeadRequest { + // The head slot reported by the peer + uint32 head_slot = 1; // Primary key (required) +} + +// Response for getting a single int_peer_head record +message GetIntPeerHeadResponse { + IntPeerHead item = 1; +} + +// Query int_peer_head data +service IntPeerHeadService { + // List records | Retrieve paginated results with optional filtering + rpc List(ListIntPeerHeadRequest) returns (ListIntPeerHeadResponse); + // Get record | Retrieve a single record by primary key + rpc Get(GetIntPeerHeadRequest) returns (GetIntPeerHeadResponse); +} diff --git a/tests/mainnet/pectra/models/fct_peer_head_last_30m.yaml b/tests/mainnet/pectra/models/fct_peer_head_last_30m.yaml new file mode 100644 index 00000000..4bf287f9 --- /dev/null +++ b/tests/mainnet/pectra/models/fct_peer_head_last_30m.yaml @@ -0,0 +1,29 @@ +model: fct_peer_head_last_30m +network: mainnet +spec: pectra +external_data: + libp2p_handle_status: + url: https://data.ethpandaops.io/xatu-cbt/mainnet/pectra/libp2p_handle_status.parquet + network_column: meta_network_name + libp2p_synthetic_heartbeat: + url: https://data.ethpandaops.io/xatu-cbt/mainnet/pectra/libp2p_synthetic_heartbeat.parquet + network_column: meta_network_name +assertions: + - name: Expected size + sql: | + SELECT + COUNT(*) AS count + FROM + 'fct_peer_head_last_30m' FINAL + expected: + count: 0 + - name: Has been scheduled at least once + sql: | + SELECT + COUNT(*) AS count + FROM + admin_cbt_scheduled FINAL + WHERE + table = 'fct_peer_head_last_30m' + expected: + count: 1 diff --git a/tests/mainnet/pectra/models/int_peer_head.yaml b/tests/mainnet/pectra/models/int_peer_head.yaml new file mode 100644 index 00000000..dcac773c --- /dev/null +++ b/tests/mainnet/pectra/models/int_peer_head.yaml @@ -0,0 +1,35 @@ +model: int_peer_head +network: mainnet +spec: pectra +external_data: + libp2p_handle_status: + url: https://data.ethpandaops.io/xatu-cbt/mainnet/pectra/libp2p_handle_status.parquet + network_column: meta_network_name + libp2p_synthetic_heartbeat: + url: https://data.ethpandaops.io/xatu-cbt/mainnet/pectra/libp2p_synthetic_heartbeat.parquet + network_column: meta_network_name +assertions: + - name: Expected bounds and size + sql: | + SELECT + COUNT(*) AS count, + MIN(event_date_time) AS min, + MAX(event_date_time) AS max + FROM + int_peer_head FINAL + expected: + count: 0 + max: null + min: null + - name: Expected admin bounds + sql: | + SELECT + fromUnixTimestamp(MAX(position + interval)) AS max, + fromUnixTimestamp(MIN(position)) AS min + FROM + admin_cbt_incremental FINAL + WHERE + table = 'int_peer_head' + expected: + max: null + min: null diff --git a/tests/mainnet/pectra/models/libp2p_handle_status.yaml b/tests/mainnet/pectra/models/libp2p_handle_status.yaml new file mode 100644 index 00000000..70d5c7da --- /dev/null +++ b/tests/mainnet/pectra/models/libp2p_handle_status.yaml @@ -0,0 +1,18 @@ +model: libp2p_handle_status +network: mainnet +spec: pectra +external_data: + libp2p_handle_status: + url: https://data.ethpandaops.io/xatu-cbt/pectra/libp2p_handle_status.parquet + network_column: meta_network_name +assertions: + - name: Has valid bounds + sql: | + SELECT + COUNT(*) AS count + FROM + admin_cbt_external FINAL + WHERE + table = 'libp2p_handle_status' + expected: + count: 1 diff --git a/tests/mainnet/pectra/models/libp2p_synthetic_heartbeat.yaml b/tests/mainnet/pectra/models/libp2p_synthetic_heartbeat.yaml new file mode 100644 index 00000000..8681c3d8 --- /dev/null +++ b/tests/mainnet/pectra/models/libp2p_synthetic_heartbeat.yaml @@ -0,0 +1,18 @@ +model: libp2p_synthetic_heartbeat +network: mainnet +spec: pectra +external_data: + libp2p_synthetic_heartbeat: + url: https://data.ethpandaops.io/xatu-cbt/pectra/libp2p_synthetic_heartbeat.parquet + network_column: meta_network_name +assertions: + - name: Has valid bounds + sql: | + SELECT + COUNT(*) AS count + FROM + admin_cbt_external FINAL + WHERE + table = 'libp2p_synthetic_heartbeat' + expected: + count: 1 diff --git a/tests/sepolia/fusaka/models/fct_peer_head_last_30m.yaml b/tests/sepolia/fusaka/models/fct_peer_head_last_30m.yaml new file mode 100644 index 00000000..018c6eac --- /dev/null +++ b/tests/sepolia/fusaka/models/fct_peer_head_last_30m.yaml @@ -0,0 +1,29 @@ +model: fct_peer_head_last_30m +network: sepolia +spec: fusaka +external_data: + libp2p_handle_status: + url: https://data.ethpandaops.io/xatu-cbt/sepolia/fusaka/libp2p_handle_status.parquet + network_column: meta_network_name + libp2p_synthetic_heartbeat: + url: https://data.ethpandaops.io/xatu-cbt/sepolia/fusaka/libp2p_synthetic_heartbeat.parquet + network_column: meta_network_name +assertions: + - name: Expected size + sql: | + SELECT + COUNT(*) AS count + FROM + 'fct_peer_head_last_30m' FINAL + expected: + count: 0 + - name: Has been scheduled at least once + sql: | + SELECT + COUNT(*) AS count + FROM + admin_cbt_scheduled FINAL + WHERE + table = 'fct_peer_head_last_30m' + expected: + count: 1 diff --git a/tests/sepolia/fusaka/models/int_peer_head.yaml b/tests/sepolia/fusaka/models/int_peer_head.yaml new file mode 100644 index 00000000..b8b86bfb --- /dev/null +++ b/tests/sepolia/fusaka/models/int_peer_head.yaml @@ -0,0 +1,35 @@ +model: int_peer_head +network: sepolia +spec: fusaka +external_data: + libp2p_handle_status: + url: https://data.ethpandaops.io/xatu-cbt/sepolia/fusaka/libp2p_handle_status.parquet + network_column: meta_network_name + libp2p_synthetic_heartbeat: + url: https://data.ethpandaops.io/xatu-cbt/sepolia/fusaka/libp2p_synthetic_heartbeat.parquet + network_column: meta_network_name +assertions: + - name: Expected bounds and size + sql: | + SELECT + COUNT(*) AS count, + MIN(event_date_time) AS min, + MAX(event_date_time) AS max + FROM + int_peer_head FINAL + expected: + count: 0 + max: null + min: null + - name: Expected admin bounds + sql: | + SELECT + fromUnixTimestamp(MAX(position + interval)) AS max, + fromUnixTimestamp(MIN(position)) AS min + FROM + admin_cbt_incremental FINAL + WHERE + table = 'int_peer_head' + expected: + max: null + min: null diff --git a/tests/sepolia/fusaka/models/libp2p_handle_status.yaml b/tests/sepolia/fusaka/models/libp2p_handle_status.yaml new file mode 100644 index 00000000..78d9119c --- /dev/null +++ b/tests/sepolia/fusaka/models/libp2p_handle_status.yaml @@ -0,0 +1,18 @@ +model: libp2p_handle_status +network: sepolia +spec: fusaka +external_data: + libp2p_handle_status: + url: https://data.ethpandaops.io/xatu-cbt/sepolia/fusaka/libp2p_handle_status.parquet + network_column: meta_network_name +assertions: + - name: Has valid bounds + sql: | + SELECT + COUNT(*) AS count + FROM + admin_cbt_external FINAL + WHERE + table = 'libp2p_handle_status' + expected: + count: 1 diff --git a/tests/sepolia/fusaka/models/libp2p_synthetic_heartbeat.yaml b/tests/sepolia/fusaka/models/libp2p_synthetic_heartbeat.yaml new file mode 100644 index 00000000..d2eba136 --- /dev/null +++ b/tests/sepolia/fusaka/models/libp2p_synthetic_heartbeat.yaml @@ -0,0 +1,18 @@ +model: libp2p_synthetic_heartbeat +network: sepolia +spec: fusaka +external_data: + libp2p_synthetic_heartbeat: + url: https://data.ethpandaops.io/xatu-cbt/sepolia/fusaka/libp2p_synthetic_heartbeat.parquet + network_column: meta_network_name +assertions: + - name: Has valid bounds + sql: | + SELECT + COUNT(*) AS count + FROM + admin_cbt_external FINAL + WHERE + table = 'libp2p_synthetic_heartbeat' + expected: + count: 1