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.
- {doublezero_telemetry-0.0.2 → doublezero_telemetry-0.0.3}/PKG-INFO +2 -1
- doublezero_telemetry-0.0.3/examples/fetch.py +123 -0
- {doublezero_telemetry-0.0.2 → doublezero_telemetry-0.0.3}/pyproject.toml +3 -1
- {doublezero_telemetry-0.0.2 → doublezero_telemetry-0.0.3}/telemetry/state.py +4 -4
- {doublezero_telemetry-0.0.2 → doublezero_telemetry-0.0.3}/uv.lock +25 -1
- {doublezero_telemetry-0.0.2 → doublezero_telemetry-0.0.3}/.gitignore +0 -0
- {doublezero_telemetry-0.0.2 → doublezero_telemetry-0.0.3}/telemetry/__init__.py +0 -0
- {doublezero_telemetry-0.0.2 → doublezero_telemetry-0.0.3}/telemetry/client.py +0 -0
- {doublezero_telemetry-0.0.2 → doublezero_telemetry-0.0.3}/telemetry/config.py +0 -0
- {doublezero_telemetry-0.0.2 → doublezero_telemetry-0.0.3}/telemetry/pda.py +0 -0
- {doublezero_telemetry-0.0.2 → doublezero_telemetry-0.0.3}/telemetry/rpc.py +0 -0
- {doublezero_telemetry-0.0.2 → doublezero_telemetry-0.0.3}/telemetry/tests/__init__.py +0 -0
- {doublezero_telemetry-0.0.2 → doublezero_telemetry-0.0.3}/telemetry/tests/test_fixtures.py +0 -0
- {doublezero_telemetry-0.0.2 → doublezero_telemetry-0.0.3}/telemetry/tests/test_pda.py +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: doublezero-telemetry
|
|
3
|
-
Version: 0.0.
|
|
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.
|
|
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
|
|
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:
|
|
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 =
|
|
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 =
|
|
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.
|
|
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" },
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|