blockmachine 0.8.2__tar.gz → 0.8.4__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 (26) hide show
  1. {blockmachine-0.8.2 → blockmachine-0.8.4}/PKG-INFO +1 -1
  2. {blockmachine-0.8.2 → blockmachine-0.8.4}/blockmachine.egg-info/PKG-INFO +1 -1
  3. {blockmachine-0.8.2 → blockmachine-0.8.4}/commands/leaderboard.py +1 -1
  4. {blockmachine-0.8.2 → blockmachine-0.8.4}/commands/miner.py +59 -8
  5. {blockmachine-0.8.2 → blockmachine-0.8.4}/pyproject.toml +1 -1
  6. {blockmachine-0.8.2 → blockmachine-0.8.4}/__init__.py +0 -0
  7. {blockmachine-0.8.2 → blockmachine-0.8.4}/auth_config.py +0 -0
  8. {blockmachine-0.8.2 → blockmachine-0.8.4}/blockmachine.egg-info/SOURCES.txt +0 -0
  9. {blockmachine-0.8.2 → blockmachine-0.8.4}/blockmachine.egg-info/dependency_links.txt +0 -0
  10. {blockmachine-0.8.2 → blockmachine-0.8.4}/blockmachine.egg-info/entry_points.txt +0 -0
  11. {blockmachine-0.8.2 → blockmachine-0.8.4}/blockmachine.egg-info/requires.txt +0 -0
  12. {blockmachine-0.8.2 → blockmachine-0.8.4}/blockmachine.egg-info/top_level.txt +0 -0
  13. {blockmachine-0.8.2 → blockmachine-0.8.4}/client.py +0 -0
  14. {blockmachine-0.8.2 → blockmachine-0.8.4}/commands/__init__.py +0 -0
  15. {blockmachine-0.8.2 → blockmachine-0.8.4}/commands/auth.py +0 -0
  16. {blockmachine-0.8.2 → blockmachine-0.8.4}/commands/validator.py +0 -0
  17. {blockmachine-0.8.2 → blockmachine-0.8.4}/config.py +0 -0
  18. {blockmachine-0.8.2 → blockmachine-0.8.4}/endpoints.py +0 -0
  19. {blockmachine-0.8.2 → blockmachine-0.8.4}/main.py +0 -0
  20. {blockmachine-0.8.2 → blockmachine-0.8.4}/settings.py +0 -0
  21. {blockmachine-0.8.2 → blockmachine-0.8.4}/setup.cfg +0 -0
  22. {blockmachine-0.8.2 → blockmachine-0.8.4}/testing.py +0 -0
  23. {blockmachine-0.8.2 → blockmachine-0.8.4}/tests/test_cli_config.py +0 -0
  24. {blockmachine-0.8.2 → blockmachine-0.8.4}/tests/test_cli_endpoints_and_testing.py +0 -0
  25. {blockmachine-0.8.2 → blockmachine-0.8.4}/tests/test_leaderboard_cli.py +0 -0
  26. {blockmachine-0.8.2 → blockmachine-0.8.4}/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: blockmachine
3
- Version: 0.8.2
3
+ Version: 0.8.4
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: blockmachine
3
- Version: 0.8.2
3
+ Version: 0.8.4
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
@@ -333,7 +333,7 @@ def _render_detail(data: dict, own_hotkey: Optional[str], archive: bool) -> None
333
333
 
334
334
  bid_label = ""
335
335
  if bid is not None and median is not None:
336
- bid_label = f" (bid: ${bid:.4f}, median: ${median:.4f})"
336
+ bid_label = f" (bid: ${bid * 1_000_000:.4f}, median: ${median * 1_000_000:.4f})"
337
337
  console.print(
338
338
  f" Price {_score_bar(pf, 3.0)} {pf:.3f}"
339
339
  f"{bid_label}{_bottleneck_label(pf)}"
@@ -357,11 +357,15 @@ _METRIC_FIELDS: list[tuple[str, str, Callable]] = [
357
357
  ("traffic_pct", "Traffic Share", lambda v: f"{v:.1f}%"),
358
358
  ("reliability", "Reliability", lambda v: f"{v:.4f}"),
359
359
  ("epochs_good", "Epochs Good", str),
360
- ("bid", "Bid", lambda v: f"${v:.6f}"),
361
- ("cohort_median", "Cohort Median", lambda v: f"${v:.6f}"),
360
+ ("bid", "Bid ($/1M CU)", lambda v: f"${v * 1_000_000:.4f}"),
361
+ ("cohort_median", "Median ($/1M CU)", lambda v: f"${v * 1_000_000:.4f}"),
362
362
  ("price_factor", "Price Factor", lambda v: f"{v:.4f}"),
363
- ("bid_archive", "Bid (Archive)", lambda v: f"${v:.6f}"),
364
- ("cohort_median_archive", "Cohort Median (Archive)", lambda v: f"${v:.6f}"),
363
+ ("bid_archive", "Bid Archive ($/1M CU)", lambda v: f"${v * 1_000_000:.4f}"),
364
+ (
365
+ "cohort_median_archive",
366
+ "Median Archive ($/1M CU)",
367
+ lambda v: f"${v * 1_000_000:.4f}",
368
+ ),
365
369
  ("price_factor_archive", "Price Factor (Archive)", lambda v: f"{v:.4f}"),
366
370
  ("routing_score_archive", "Routing Score (Archive)", lambda v: f"{v:.4f}"),
367
371
  ]
@@ -453,13 +457,17 @@ def update(
453
457
  alias: str = typer.Argument(None, help="Node alias or ID"),
454
458
  new_alias: str = typer.Option(None, "--alias", "-a", help="New alias"),
455
459
  endpoint: str = typer.Option(None, "--endpoint", "-e", help="New endpoint"),
460
+ repin: bool = typer.Option(
461
+ False, "--repin", help="Re-detect and update TLS cert fingerprint"
462
+ ),
456
463
  ) -> None:
457
- """Update a node's alias or endpoint."""
464
+ """Update a node's alias, endpoint, or TLS fingerprint."""
458
465
  alias = _get_alias(alias)
459
466
 
460
- if not new_alias and not endpoint:
467
+ if not new_alias and not endpoint and not repin:
461
468
  console.print(
462
- "[yellow]Nothing to update. Specify --alias or --endpoint[/yellow]"
469
+ "[yellow]Nothing to update."
470
+ " Specify --alias, --endpoint, or --repin[/yellow]"
463
471
  )
464
472
  return
465
473
 
@@ -472,6 +480,32 @@ def update(
472
480
 
473
481
  with RegistryClient(config) as client:
474
482
  node_id = _resolve_node(client, alias)
483
+
484
+ if repin:
485
+ node_resp = client.get(f"/nodes/{node_id}")
486
+ if node_resp.status_code != 200:
487
+ console.print(f"[red]Error fetching node:[/red] {node_resp.text}")
488
+ raise typer.Exit(1)
489
+ node_endpoint = endpoint or node_resp.json()["endpoint"]
490
+ if not is_ip_endpoint(node_endpoint):
491
+ console.print(
492
+ "[yellow]--repin ignored:"
493
+ " only applies to IP-based endpoints[/yellow]"
494
+ )
495
+ else:
496
+ fp = get_cert_fingerprint(node_endpoint)
497
+ if fp:
498
+ update_data["cert_fingerprint"] = fp
499
+ console.print(f"[dim]New TLS fingerprint: {fp}[/dim]")
500
+ else:
501
+ console.print(
502
+ "[red]Could not fetch TLS certificate from endpoint[/red]"
503
+ )
504
+ raise typer.Exit(1)
505
+
506
+ if not update_data:
507
+ return
508
+
475
509
  response = client.patch(f"/nodes/{node_id}", json=update_data)
476
510
 
477
511
  if response.status_code == 200:
@@ -518,6 +552,7 @@ def test(
518
552
  automatically. Use --endpoint and --secret for pre-registration
519
553
  testing.
520
554
  """
555
+ stored_fingerprint: Optional[str] = None
521
556
  if not endpoint:
522
557
  alias = _get_alias(alias)
523
558
  config = load_config()
@@ -529,6 +564,7 @@ def test(
529
564
  raise typer.Exit(1)
530
565
  node = response.json()
531
566
  endpoint = node["endpoint"]
567
+ stored_fingerprint = node.get("cert_fingerprint")
532
568
  if not secret:
533
569
  secret = _fetch_active_secret(client, node_id)
534
570
  console.print(f"[bold]Alias:[/bold] {alias}")
@@ -551,12 +587,27 @@ def test(
551
587
  if tls_ok:
552
588
  is_ip = is_ip_endpoint(endpoint)
553
589
  mode = "pinned" if is_ip else "CA-verified"
554
- fp_short = fingerprint[:16] + "..." if fingerprint else "none"
590
+ fp_short = _truncate(fingerprint, 16) if fingerprint else "none"
555
591
  console.print(f"[green]OK[/green] ({mode}, {fp_short})")
556
592
  else:
557
593
  console.print(f"[red]FAIL[/red] {tls_msg}")
558
594
  all_ok = False
559
595
 
596
+ if stored_fingerprint and fingerprint:
597
+ console.print("Cert pinning... ", end="")
598
+ if stored_fingerprint == fingerprint:
599
+ console.print("[green]OK[/green] (matches registry)")
600
+ else:
601
+ console.print("[red]MISMATCH[/red]")
602
+ console.print(
603
+ f"[yellow] ↳ Registry: {_truncate(stored_fingerprint, 16)}[/yellow]"
604
+ )
605
+ console.print(
606
+ f"[yellow] ↳ Live: {_truncate(fingerprint, 16)}[/yellow]"
607
+ )
608
+ console.print("[yellow] ↳ Run 'bm miner update --repin' to fix[/yellow]")
609
+ all_ok = False
610
+
560
611
  # 2. Health
561
612
  console.print("Health check... ", end="")
562
613
  health_ok, health_msg = test_health(hostname)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "blockmachine"
7
- version = "0.8.2"
7
+ version = "0.8.4"
8
8
  description = "Blockmachine CLI - Miner and validator operator interface"
9
9
  requires-python = ">=3.10"
10
10
  license = "MIT"
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