doublezero-telemetry 0.0.2__tar.gz → 0.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: doublezero-telemetry
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: DoubleZero Telemetry SDK
5
5
  Requires-Python: >=3.10
6
6
  Requires-Dist: borsh-incremental
7
+ Requires-Dist: doublezero-serviceability
7
8
  Requires-Dist: httpx>=0.27
8
9
  Requires-Dist: solana>=0.35
9
10
  Requires-Dist: solders>=0.21
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env python3
2
+ """Example CLI that fetches and displays telemetry data."""
3
+
4
+ import argparse
5
+
6
+ from solders.pubkey import Pubkey # type: ignore[import-untyped]
7
+
8
+ from serviceability.client import Client as ServiceabilityClient
9
+ from telemetry.client import Client as TelemetryClient
10
+ from telemetry.config import LEDGER_RPC_URLS
11
+ from telemetry.rpc import new_rpc_client
12
+
13
+
14
+ def main() -> None:
15
+ parser = argparse.ArgumentParser(description="Fetch telemetry data")
16
+ parser.add_argument(
17
+ "--env",
18
+ default="mainnet-beta",
19
+ choices=["mainnet-beta", "testnet", "devnet", "localnet"],
20
+ help="Environment to connect to",
21
+ )
22
+ parser.add_argument(
23
+ "--epoch",
24
+ type=int,
25
+ default=0,
26
+ help="Epoch to fetch samples for (0 = current epoch)",
27
+ )
28
+ args = parser.parse_args()
29
+
30
+ print(f"Fetching telemetry data from {args.env}...\n")
31
+
32
+ # First, get serviceability data to discover devices and links
33
+ svc_client = ServiceabilityClient.from_env(args.env)
34
+ svc_data = svc_client.get_program_data()
35
+
36
+ print("=== Network Overview ===")
37
+ print(f"Devices: {len(svc_data.devices)}")
38
+ print(f"Links: {len(svc_data.links)}")
39
+ print()
40
+
41
+ if not svc_data.links:
42
+ print("No links found - no telemetry data to fetch.")
43
+ return
44
+
45
+ # Build device code map for display
46
+ device_codes: dict[str, str] = {}
47
+ device_pks: dict[str, Pubkey] = {}
48
+ for dev in svc_data.devices:
49
+ pk_str = str(dev.owner) # Using owner as pubkey proxy
50
+ device_codes[pk_str] = dev.code
51
+ device_pks[dev.code] = dev.owner
52
+
53
+ # Create telemetry client
54
+ tel_client = TelemetryClient.from_env(args.env)
55
+
56
+ # Determine which epoch to use
57
+ target_epoch = args.epoch
58
+ if target_epoch == 0:
59
+ # Get current epoch from RPC
60
+ rpc = new_rpc_client(LEDGER_RPC_URLS[args.env])
61
+ epoch_info = rpc.get_epoch_info()
62
+ target_epoch = epoch_info.value.epoch
63
+
64
+ print(f"=== Device Latency Samples (epoch {target_epoch}) ===")
65
+
66
+ samples_found = 0
67
+ for link in svc_data.links:
68
+ side_a_pk = link.side_a_pub_key
69
+ side_z_pk = link.side_z_pub_key
70
+ link_pk = link.owner # Using owner as link pubkey proxy
71
+
72
+ # Find device codes
73
+ side_a_code = "unknown"
74
+ side_z_code = "unknown"
75
+ for dev in svc_data.devices:
76
+ if str(dev.owner) == str(side_a_pk):
77
+ side_a_code = dev.code
78
+ if str(dev.owner) == str(side_z_pk):
79
+ side_z_code = dev.code
80
+
81
+ # Try both directions
82
+ for origin_pk, target_pk, o_code, t_code in [
83
+ (side_a_pk, side_z_pk, side_a_code, side_z_code),
84
+ (side_z_pk, side_a_pk, side_z_code, side_a_code),
85
+ ]:
86
+ try:
87
+ samples = tel_client.get_device_latency_samples(
88
+ origin_pk, target_pk, link_pk, target_epoch
89
+ )
90
+ except Exception:
91
+ # Account likely doesn't exist for this epoch
92
+ continue
93
+
94
+ samples_found += 1
95
+ sample_count = len(samples.samples)
96
+
97
+ if sample_count == 0:
98
+ print(f" {o_code} -> {t_code} ({link.code}): initialized, no samples yet")
99
+ continue
100
+
101
+ # Calculate stats
102
+ total = sum(samples.samples)
103
+ min_val = min(samples.samples)
104
+ max_val = max(samples.samples)
105
+ avg_us = total / sample_count
106
+ avg_ms = avg_us / 1000.0
107
+ min_ms = min_val / 1000.0
108
+ max_ms = max_val / 1000.0
109
+
110
+ print(
111
+ f" {o_code} -> {t_code} ({link.code}): {sample_count} samples, "
112
+ f"avg {avg_ms:.2f}ms, min {min_ms:.2f}ms, max {max_ms:.2f}ms"
113
+ )
114
+
115
+ if samples_found == 0:
116
+ print(f" No samples found for epoch {target_epoch}. Try a different epoch with --epoch flag.")
117
+
118
+ print()
119
+ print("Done.")
120
+
121
+
122
+ if __name__ == "__main__":
123
+ main()
@@ -1,10 +1,11 @@
1
1
  [project]
2
2
  name = "doublezero-telemetry"
3
- version = "0.0.2"
3
+ version = "0.0.3"
4
4
  description = "DoubleZero Telemetry SDK"
5
5
  requires-python = ">=3.10"
6
6
  dependencies = [
7
7
  "borsh-incremental",
8
+ "doublezero-serviceability",
8
9
  "solana>=0.35",
9
10
  "solders>=0.21",
10
11
  "httpx>=0.27",
@@ -27,3 +28,4 @@ dev = [
27
28
 
28
29
  [tool.uv.sources]
29
30
  borsh-incremental = { path = "../../borsh-incremental/python", editable = true }
31
+ doublezero-serviceability = { path = "../../serviceability/python", editable = true }
@@ -9,7 +9,7 @@ from __future__ import annotations
9
9
 
10
10
  from dataclasses import dataclass, field
11
11
 
12
- from borsh_incremental import IncrementalReader
12
+ from borsh_incremental import DefensiveReader
13
13
  from solders.pubkey import Pubkey # type: ignore[import-untyped]
14
14
 
15
15
 
@@ -23,7 +23,7 @@ MAX_INTERNET_LATENCY_SAMPLES_PER_ACCOUNT = 3_000
23
23
  DEVICE_LATENCY_HEADER_SIZE = 1 + 8 + 32 * 6 + 8 + 8 + 4 + 128
24
24
 
25
25
 
26
- def _read_pubkey(r: IncrementalReader) -> Pubkey:
26
+ def _read_pubkey(r: DefensiveReader) -> Pubkey:
27
27
  return Pubkey.from_bytes(r.read_pubkey_raw())
28
28
 
29
29
 
@@ -49,7 +49,7 @@ class DeviceLatencySamples:
49
49
  f"data too short for device latency header: {len(data)} < {DEVICE_LATENCY_HEADER_SIZE}"
50
50
  )
51
51
 
52
- r = IncrementalReader(data)
52
+ r = DefensiveReader(data)
53
53
 
54
54
  account_type = r.read_u8()
55
55
  epoch = r.read_u64()
@@ -106,7 +106,7 @@ class InternetLatencySamples:
106
106
  if len(data) < 10:
107
107
  raise ValueError("data too short")
108
108
 
109
- r = IncrementalReader(data)
109
+ r = DefensiveReader(data)
110
110
 
111
111
  account_type = r.read_u8()
112
112
  epoch = r.read_u64()
@@ -66,12 +66,35 @@ wheels = [
66
66
  { url = "https://files.pythonhosted.org/packages/8c/0c/2db6f7e1ae9795e436c6a0dc0bc38b12b8c8a228cb63203e24190b755b3b/construct_typing-0.7.0-py3-none-any.whl", hash = "sha256:c92383c6e8e5d07ba25811c8d5163820458d821e73bb1006541f43f89788646c", size = 24350, upload-time = "2025-10-27T19:30:27.505Z" },
67
67
  ]
68
68
 
69
+ [[package]]
70
+ name = "doublezero-serviceability"
71
+ version = "0.0.2"
72
+ source = { editable = "../../serviceability/python" }
73
+ dependencies = [
74
+ { name = "borsh-incremental" },
75
+ { name = "httpx" },
76
+ { name = "solana" },
77
+ { name = "solders" },
78
+ ]
79
+
80
+ [package.metadata]
81
+ requires-dist = [
82
+ { name = "borsh-incremental", editable = "../../borsh-incremental/python" },
83
+ { name = "httpx", specifier = ">=0.27" },
84
+ { name = "solana", specifier = ">=0.35" },
85
+ { name = "solders", specifier = ">=0.21" },
86
+ ]
87
+
88
+ [package.metadata.requires-dev]
89
+ dev = [{ name = "pytest", specifier = ">=9.0.2" }]
90
+
69
91
  [[package]]
70
92
  name = "doublezero-telemetry"
71
- version = "0.0.1"
93
+ version = "0.0.2"
72
94
  source = { editable = "." }
73
95
  dependencies = [
74
96
  { name = "borsh-incremental" },
97
+ { name = "doublezero-serviceability" },
75
98
  { name = "httpx" },
76
99
  { name = "solana" },
77
100
  { name = "solders" },
@@ -85,6 +108,7 @@ dev = [
85
108
  [package.metadata]
86
109
  requires-dist = [
87
110
  { name = "borsh-incremental", editable = "../../borsh-incremental/python" },
111
+ { name = "doublezero-serviceability", editable = "../../serviceability/python" },
88
112
  { name = "httpx", specifier = ">=0.27" },
89
113
  { name = "solana", specifier = ">=0.35" },
90
114
  { name = "solders", specifier = ">=0.21" },