From 0a195f796267b32595d593e6d51da45473177fcb Mon Sep 17 00:00:00 2001 From: Virgil Date: Sat, 4 Apr 2026 11:53:03 +0000 Subject: [PATCH] feat(proxy): add UUID session ids and custom diff buckets Co-Authored-By: Virgil --- miner_runtime.go | 15 +++++++++++- miner_runtime_test.go | 4 +++- proxy_runtime.go | 4 ++++ stats_workers_test.go | 47 ++++++++++++++++++++++++++++++++++++++ worker.go | 53 ++++++++++++++++++++++++++++++++++--------- 5 files changed, 110 insertions(+), 13 deletions(-) diff --git a/miner_runtime.go b/miner_runtime.go index a85ab0d..3a70260 100644 --- a/miner_runtime.go +++ b/miner_runtime.go @@ -397,7 +397,20 @@ func (m *Miner) Expire() { func newRPCID() string { value := make([]byte, 16) _, _ = rand.Read(value) - return hex.EncodeToString(value) + value[6] = (value[6] & 0x0f) | 0x40 + value[8] = (value[8] & 0x3f) | 0x80 + + encoded := make([]byte, 36) + hex.Encode(encoded[0:8], value[0:4]) + encoded[8] = '-' + hex.Encode(encoded[9:13], value[4:6]) + encoded[13] = '-' + hex.Encode(encoded[14:18], value[6:8]) + encoded[18] = '-' + hex.Encode(encoded[19:23], value[8:10]) + encoded[23] = '-' + hex.Encode(encoded[24:36], value[10:16]) + return string(encoded) } func (m *Miner) RemoteAddr() net.Addr { diff --git a/miner_runtime_test.go b/miner_runtime_test.go index 57a73cc..82652eb 100644 --- a/miner_runtime_test.go +++ b/miner_runtime_test.go @@ -4,6 +4,7 @@ import ( "bufio" "encoding/json" "net" + "strings" "testing" "time" ) @@ -46,7 +47,8 @@ func TestMiner_Login_Good(t *testing.T) { } result := response["result"].(map[string]interface{}) - if result["status"] != "OK" || result["id"] == "" { + id, _ := result["id"].(string) + if result["status"] != "OK" || len(id) != 36 || id[8] != '-' || id[13] != '-' || id[18] != '-' || id[23] != '-' || id[14] != '4' || !strings.ContainsAny(string(id[19]), "89ab") { t.Fatalf("unexpected login response: %#v", response) } } diff --git a/proxy_runtime.go b/proxy_runtime.go index 1502f1b..61bad57 100644 --- a/proxy_runtime.go +++ b/proxy_runtime.go @@ -24,6 +24,7 @@ func New(cfg *Config) (*Proxy, error) { customDiff := NewCustomDiff(cfg.CustomDiff) events.Subscribe(EventLogin, customDiff.OnLogin) workers := NewWorkers(cfg.Workers, events) + workers.SetCustomDiffStats(cfg.CustomDiffStats) splitter := newSplitter(cfg, events) proxyValue := &Proxy{ @@ -229,6 +230,9 @@ func (p *Proxy) Reload(cfg *Config) { if p.customDiff != nil { p.customDiff.SetGlobalDiff(p.config.CustomDiff) } + if p.workers != nil { + p.workers.SetCustomDiffStats(p.config.CustomDiffStats) + } if p.rateLimiter != nil { p.rateLimiter.SetConfig(p.config.RateLimit) } diff --git a/stats_workers_test.go b/stats_workers_test.go index 8eb6acc..6bff7b0 100644 --- a/stats_workers_test.go +++ b/stats_workers_test.go @@ -92,3 +92,50 @@ func TestWorkers_List_Ugly(t *testing.T) { t.Fatalf("unexpected worker records: %+v", records) } } + +func TestWorkers_CustomDiffStats_Good(t *testing.T) { + bus := NewEventBus() + workers := NewWorkers(WorkersByUser, bus) + workers.SetCustomDiffStats(true) + + firstMiner := &Miner{id: 1, user: "wallet", customDiff: 1000} + secondMiner := &Miner{id: 2, user: "wallet", customDiff: 2000} + bus.Dispatch(Event{Type: EventLogin, Miner: firstMiner}) + bus.Dispatch(Event{Type: EventLogin, Miner: secondMiner}) + + records := workers.List() + if len(records) != 2 || records[0].Name == records[1].Name { + t.Fatalf("expected separate custom-diff buckets, got %+v", records) + } +} + +func TestWorkers_CustomDiffStats_Bad(t *testing.T) { + bus := NewEventBus() + workers := NewWorkers(WorkersByUser, bus) + workers.SetCustomDiffStats(true) + + firstMiner := &Miner{id: 1, user: "wallet", customDiff: 1000} + secondMiner := &Miner{id: 2, user: "wallet", customDiff: 1000} + bus.Dispatch(Event{Type: EventLogin, Miner: firstMiner}) + bus.Dispatch(Event{Type: EventLogin, Miner: secondMiner}) + + records := workers.List() + if len(records) != 1 { + t.Fatalf("expected identical custom-diff bucket to merge, got %+v", records) + } +} + +func TestWorkers_CustomDiffStats_Ugly(t *testing.T) { + bus := NewEventBus() + workers := NewWorkers(WorkersByUser, bus) + + firstMiner := &Miner{id: 1, user: "wallet", customDiff: 1000} + secondMiner := &Miner{id: 2, user: "wallet", customDiff: 2000} + bus.Dispatch(Event{Type: EventLogin, Miner: firstMiner}) + bus.Dispatch(Event{Type: EventLogin, Miner: secondMiner}) + + records := workers.List() + if len(records) != 1 || records[0].Name != "wallet" { + t.Fatalf("expected default worker bucketing to ignore custom diff, got %+v", records) + } +} diff --git a/worker.go b/worker.go index 2a52a03..d29349f 100644 --- a/worker.go +++ b/worker.go @@ -1,6 +1,7 @@ package proxy import ( + "strconv" "sync" "time" ) @@ -10,11 +11,12 @@ import ( // // w := proxy.NewWorkers(proxy.WorkersByRigID, bus) type Workers struct { - mode WorkersMode - entries []WorkerRecord // ordered by first-seen (stable) - nameIndex map[string]int // workerName → entries index - idIndex map[int64]int // minerID → entries index - mu sync.RWMutex + mode WorkersMode + customDiffStats bool + entries []WorkerRecord // ordered by first-seen (stable) + nameIndex map[string]int // workerName → entries index + idIndex map[int64]int // minerID → entries index + mu sync.RWMutex } // WorkerRecord is the per-identity aggregate. @@ -66,6 +68,19 @@ func NewWorkers(mode WorkersMode, bus *EventBus) *Workers { return workers } +// SetCustomDiffStats toggles per-custom-difficulty worker bucketing. +// +// workers.SetCustomDiffStats(true) +func (w *Workers) SetCustomDiffStats(enabled bool) { + if w == nil { + return + } + + w.mu.Lock() + w.customDiffStats = enabled + w.mu.Unlock() +} + // List returns a snapshot of all worker records in first-seen order. // // records := workers.List() @@ -186,21 +201,37 @@ func (w *Workers) updateShare(event Event, accepted bool) { } func (w *Workers) workerName(miner *Miner) string { + if miner == nil { + return "" + } + + w.mu.RLock() + customDiffStats := w.customDiffStats + w.mu.RUnlock() + + name := "" switch w.mode { case WorkersByRigID: if miner.RigID() != "" { - return miner.RigID() + name = miner.RigID() + } else { + name = miner.User() } - return miner.User() case WorkersByUser: - return miner.User() + name = miner.User() case WorkersByPass: - return miner.Password() + name = miner.Password() case WorkersByAgent: - return miner.Agent() + name = miner.Agent() case WorkersByIP: - return miner.IP() + name = miner.IP() default: return "" } + + if !customDiffStats || miner.CustomDiff() == 0 || name == "" { + return name + } + + return name + "+cd" + strconv.FormatUint(miner.CustomDiff(), 10) }