blockmachine 0.22.0__tar.gz → 0.23.0__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.
Files changed (38) hide show
  1. {blockmachine-0.22.0 → blockmachine-0.23.0}/PKG-INFO +2 -2
  2. {blockmachine-0.22.0 → blockmachine-0.23.0}/blockmachine.egg-info/PKG-INFO +2 -2
  3. {blockmachine-0.22.0 → blockmachine-0.23.0}/blockmachine.egg-info/SOURCES.txt +4 -2
  4. {blockmachine-0.22.0 → blockmachine-0.23.0}/blockmachine.egg-info/requires.txt +1 -1
  5. {blockmachine-0.22.0 → blockmachine-0.23.0}/commands/epoch.py +53 -7
  6. {blockmachine-0.22.0 → blockmachine-0.23.0}/commands/leaderboard.py +10 -11
  7. {blockmachine-0.22.0 → blockmachine-0.23.0}/commands/miner.py +43 -544
  8. {blockmachine-0.22.0 → blockmachine-0.23.0}/main.py +0 -11
  9. {blockmachine-0.22.0 → blockmachine-0.23.0}/pyproject.toml +2 -2
  10. {blockmachine-0.22.0 → blockmachine-0.23.0}/settings.py +7 -25
  11. {blockmachine-0.22.0 → blockmachine-0.23.0}/tests/test_cli_config.py +4 -43
  12. blockmachine-0.23.0/tests/test_cli_help.py +42 -0
  13. {blockmachine-0.22.0 → blockmachine-0.23.0}/tests/test_epoch_payout_cli.py +101 -3
  14. {blockmachine-0.22.0 → blockmachine-0.23.0}/tests/test_leaderboard_cli.py +14 -4
  15. {blockmachine-0.22.0 → blockmachine-0.23.0}/tests/test_miner_add_class.py +0 -1
  16. {blockmachine-0.22.0 → blockmachine-0.23.0}/tests/test_miner_eligibility.py +24 -0
  17. blockmachine-0.23.0/tests/test_miner_eth_tier.py +61 -0
  18. blockmachine-0.23.0/tests/test_miner_metrics.py +20 -0
  19. blockmachine-0.23.0/tests/test_miner_pricing.py +41 -0
  20. blockmachine-0.22.0/tests/test_miner_capacity.py +0 -451
  21. blockmachine-0.22.0/tests/test_miner_eth_tier.py +0 -195
  22. {blockmachine-0.22.0 → blockmachine-0.23.0}/__init__.py +0 -0
  23. {blockmachine-0.22.0 → blockmachine-0.23.0}/auth_config.py +0 -0
  24. {blockmachine-0.22.0 → blockmachine-0.23.0}/blockmachine.egg-info/dependency_links.txt +0 -0
  25. {blockmachine-0.22.0 → blockmachine-0.23.0}/blockmachine.egg-info/entry_points.txt +0 -0
  26. {blockmachine-0.22.0 → blockmachine-0.23.0}/blockmachine.egg-info/top_level.txt +0 -0
  27. {blockmachine-0.22.0 → blockmachine-0.23.0}/client.py +0 -0
  28. {blockmachine-0.22.0 → blockmachine-0.23.0}/commands/__init__.py +0 -0
  29. {blockmachine-0.22.0 → blockmachine-0.23.0}/commands/auth.py +0 -0
  30. {blockmachine-0.22.0 → blockmachine-0.23.0}/commands/validator.py +0 -0
  31. {blockmachine-0.22.0 → blockmachine-0.23.0}/config.py +0 -0
  32. {blockmachine-0.22.0 → blockmachine-0.23.0}/endpoints.py +0 -0
  33. {blockmachine-0.22.0 → blockmachine-0.23.0}/setup.cfg +0 -0
  34. {blockmachine-0.22.0 → blockmachine-0.23.0}/testing.py +0 -0
  35. {blockmachine-0.22.0 → blockmachine-0.23.0}/tests/test_cli_endpoints_and_testing.py +0 -0
  36. {blockmachine-0.22.0 → blockmachine-0.23.0}/tests/test_miner_ban_line.py +0 -0
  37. {blockmachine-0.22.0 → blockmachine-0.23.0}/tests/test_miner_compat_reason.py +0 -0
  38. {blockmachine-0.22.0 → blockmachine-0.23.0}/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: blockmachine
3
- Version: 0.22.0
3
+ Version: 0.23.0
4
4
  Summary: Blockmachine CLI - Miner and validator operator interface
5
5
  License-Expression: MIT
6
6
  Project-URL: Homepage, https://github.com/taostat/blockmachine
@@ -8,7 +8,7 @@ Classifier: Development Status :: 3 - Alpha
8
8
  Classifier: Environment :: Console
9
9
  Classifier: Programming Language :: Python :: 3
10
10
  Requires-Python: >=3.10
11
- Requires-Dist: typer[all]<0.26.0,>=0.9.0
11
+ Requires-Dist: typer<0.26.0,>=0.9.0
12
12
  Requires-Dist: rich>=13.7.0
13
13
  Requires-Dist: httpx>=0.27.0
14
14
  Requires-Dist: websockets>=13.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: blockmachine
3
- Version: 0.22.0
3
+ Version: 0.23.0
4
4
  Summary: Blockmachine CLI - Miner and validator operator interface
5
5
  License-Expression: MIT
6
6
  Project-URL: Homepage, https://github.com/taostat/blockmachine
@@ -8,7 +8,7 @@ Classifier: Development Status :: 3 - Alpha
8
8
  Classifier: Environment :: Console
9
9
  Classifier: Programming Language :: Python :: 3
10
10
  Requires-Python: >=3.10
11
- Requires-Dist: typer[all]<0.26.0,>=0.9.0
11
+ Requires-Dist: typer<0.26.0,>=0.9.0
12
12
  Requires-Dist: rich>=13.7.0
13
13
  Requires-Dist: httpx>=0.27.0
14
14
  Requires-Dist: websockets>=13.0
@@ -31,11 +31,13 @@ commands/miner.py
31
31
  commands/validator.py
32
32
  tests/test_cli_config.py
33
33
  tests/test_cli_endpoints_and_testing.py
34
+ tests/test_cli_help.py
34
35
  tests/test_epoch_payout_cli.py
35
36
  tests/test_leaderboard_cli.py
36
37
  tests/test_miner_add_class.py
37
38
  tests/test_miner_ban_line.py
38
- tests/test_miner_capacity.py
39
39
  tests/test_miner_compat_reason.py
40
40
  tests/test_miner_eligibility.py
41
- tests/test_miner_eth_tier.py
41
+ tests/test_miner_eth_tier.py
42
+ tests/test_miner_metrics.py
43
+ tests/test_miner_pricing.py
@@ -1,4 +1,4 @@
1
- typer[all]<0.26.0,>=0.9.0
1
+ typer<0.26.0,>=0.9.0
2
2
  rich>=13.7.0
3
3
  httpx>=0.27.0
4
4
  websockets>=13.0
@@ -84,7 +84,7 @@ def render_payout(body: dict, top: int = TOP_MINERS) -> list[str]:
84
84
 
85
85
  lines.append(
86
86
  f" {'UID':<4} {'alpha':>9} {'USD':>9} {'share':>5} "
87
- "breakdown (chain/class → α)"
87
+ "breakdown (chain/request class → α)"
88
88
  )
89
89
  for m in miners[:top]:
90
90
  lines.append(
@@ -103,27 +103,69 @@ def render_payout(body: dict, top: int = TOP_MINERS) -> list[str]:
103
103
  return lines
104
104
 
105
105
 
106
+ def _has_cu_split(miner: dict) -> bool:
107
+ """Does this body separate served CU from the base-incentive subsidy?
108
+
109
+ Registries built before taostat/blockmachine_playground#1529 send one
110
+ unqualified ``cu`` and nothing else. Printing zero served CU against
111
+ those would be a new lie, so the old single column is kept for them.
112
+ """
113
+ return "cu_served" in miner and "cu_base_incentive" in miner
114
+
115
+
106
116
  def render_miner(body: dict, miner: dict) -> list[str]:
107
- """One miner with every (chain, class) line."""
117
+ """One miner with every chain and request-class line."""
108
118
  header = render_payout(body)
109
119
  lines = header[: header.index("")]
120
+ split = _has_cu_split(miner)
121
+ cu_total = int(miner.get("cu_total") or 0)
110
122
  lines.append("")
111
123
  lines.append(
112
124
  f"UID {miner.get('uid')} {miner.get('hotkey')}\n"
113
125
  f" {float(miner.get('alpha') or 0):.1f} α "
114
126
  f"(${_fmt_usd(miner.get('usd'))}, "
115
- f"{float(miner.get('share') or 0) * 100:.1f}% of the pool, "
116
- f"{int(miner.get('cu_total') or 0):,} CU)"
127
+ f"{float(miner.get('share') or 0) * 100:.1f}% of the pool"
128
+ + (")" if split else f", {cu_total:,} CU)")
117
129
  )
130
+ if split:
131
+ lines.append(
132
+ f" {cu_total:,} CU: {int(miner.get('cu_served') or 0):,} served "
133
+ f"+ {int(miner.get('cu_base_incentive') or 0):,} base incentive"
134
+ )
118
135
  lines.append("")
119
- lines.append(f" {'chain/class':<18} {'CU':>15} {'alpha':>9} {'USD':>9}")
136
+ if split:
137
+ lines.append(
138
+ f" {'chain/request class':<22} {'served CU':>15} "
139
+ f"{'base incentive CU':>19} {'alpha':>9} {'USD':>9}"
140
+ )
141
+ else:
142
+ lines.append(
143
+ f" {'chain/request class':<22} {'CU':>15} {'alpha':>9} {'USD':>9}"
144
+ )
120
145
  for e in miner.get("breakdown") or []:
121
146
  node = f"{e.get('chain')}/{e.get('node_class')}"
147
+ cu_col = (
148
+ f"{int(e.get('cu_served') or 0):>15,} "
149
+ f"{int(e.get('cu_base_incentive') or 0):>19,}"
150
+ if split
151
+ else f"{int(e.get('cu') or 0):>15,}"
152
+ )
122
153
  lines.append(
123
- f" {node:<18} {int(e.get('cu') or 0):>15,} "
154
+ f" {node:<18} {cu_col} "
124
155
  f"{float(e.get('alpha') or 0):>9.1f} {_fmt_usd(e.get('usd')):>9}"
125
156
  )
126
157
  lines.append("")
158
+ if split:
159
+ lines.append(
160
+ "Served CU is the customer traffic this miner answered. Base incentive "
161
+ "CU is the"
162
+ )
163
+ lines.append(
164
+ "subnet's own top-up, injected as CU — nobody sent those requests. "
165
+ "Both count"
166
+ )
167
+ lines.append("toward the payout, and together they are the CU total above.")
168
+ lines.append("")
127
169
  lines.append(
128
170
  "USD is an estimate at the α price the finalizer recorded; the chain pays in α."
129
171
  )
@@ -144,8 +186,12 @@ def payout(
144
186
 
145
187
  Per UID: alpha, USD (an estimate at the price recorded when the epoch
146
188
  was finalized), share of the miner pool, and the alpha split by chain
147
- and node class. Available the moment an epoch finalizes; the chain pays
189
+ and request class. Available the moment an epoch finalizes; the chain pays
148
190
  it out over the following epoch.
191
+
192
+ With --uid, CU is shown as two columns: the customer traffic the miner
193
+ answered, and the base-incentive subsidy injected as synthetic CU. Both
194
+ count toward the payout; only the first is traffic.
149
195
  """
150
196
  path = "/epochs/latest/payout" if epoch is None else f"/epochs/{epoch}/payout"
151
197
  with RegistryClient(load_config()) as client:
@@ -238,9 +238,8 @@ def _render_default(
238
238
  ) -> None:
239
239
  """Render the default leaderboard view (Option B).
240
240
 
241
- When ``verbose`` is True, ETH node sub-rows include the raw
242
- five-flag capability string (``A P T D X``) after the tier label so
243
- operators can inspect what the gateway actually probed.
241
+ When ``verbose`` is True, ETH node sub-rows include the three
242
+ capability flags (``A P X``) after the tier label.
244
243
  """
245
244
  miners = data.get("miners", [])
246
245
  epoch = data.get("epoch")
@@ -363,8 +362,8 @@ def _render_default(
363
362
  def _recompute_shares(miners: list[dict], archive: bool) -> list[dict]:
364
363
  """Recompute routing scores and traffic shares for the selected dimension.
365
364
 
366
- When archive=True, filters to archive-capable nodes only and uses
367
- routing_score_archive / price_factor_archive.
365
+ When archive=True, filters to nodes marked ``is_archive`` or
366
+ ``serves_proofs`` and uses routing_score_archive / price_factor_archive.
368
367
  Adds _score, _share, _price_factor to each miner and _share to each node.
369
368
  """
370
369
  results = []
@@ -373,7 +372,7 @@ def _recompute_shares(miners: list[dict], archive: bool) -> list[dict]:
373
372
  for miner in miners:
374
373
  nodes = miner.get("nodes", [])
375
374
  if archive:
376
- nodes = [n for n in nodes if n.get("is_archive", False)]
375
+ nodes = [n for n in nodes if n.get("is_archive") or n.get("serves_proofs")]
377
376
  miner_score = 0.0
378
377
  for node in nodes:
379
378
  ns = _node_score_field(node, "routing_score", archive) or 0.0
@@ -503,10 +502,10 @@ def _render_detail(
503
502
  f"{p95_label}{_bottleneck_label(lat)}"
504
503
  )
505
504
 
506
- # Reliability saturates at 7 good epochs (gateway cap, #952);
505
+ # Reliability saturates at 3 good epochs (gateway cap);
507
506
  # more history exists but no longer buys score.
508
507
  ep_label = (
509
- f" ({epochs_good} good epochs; score saturates at 7)"
508
+ f" ({epochs_good} good epochs; score saturates at 3)"
510
509
  if epochs_good is not None
511
510
  else ""
512
511
  )
@@ -560,15 +559,15 @@ def show(
560
559
  None,
561
560
  "--chain",
562
561
  "-c",
563
- help="Filter to a single chain (e.g. eth, tao, bsc, base, polygon, optimism, arbitrum, avalanche, scroll, mantle, robinhood, tron). Default: all chains.",
562
+ help="Filter to a single chain (e.g. eth, tao, bsc, base, polygon, optimism, arbitrum, avalanche, arc, scroll, mantle, robinhood, tron). Default: all chains.",
564
563
  ),
565
564
  verbose: bool = typer.Option(
566
565
  False,
567
566
  "--verbose",
568
567
  "-v",
569
568
  help=(
570
- "For ETH nodes, show raw capability flags (A P T D X = "
571
- "archive, proof, trace, debug, audit-compatible) alongside "
569
+ "For ETH nodes, show raw capability flags (A P X = "
570
+ "archive, proof, audit-compatible) alongside "
572
571
  "the tier label."
573
572
  ),
574
573
  ),