From 22f1420d1c0e3cd3468aa4b9794dfe56e1cf90e0 Mon Sep 17 00:00:00 2001 From: Virgil Date: Sat, 4 Apr 2026 12:11:48 +0000 Subject: [PATCH] fix(splitter): tighten stale job validation Co-Authored-By: Virgil --- splitter/nicehash/storage.go | 4 ++-- splitter/nicehash/storage_test.go | 9 +++++++++ splitter/simple/mapper.go | 4 ++-- splitter/simple/splitter_test.go | 12 ++++++++++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/splitter/nicehash/storage.go b/splitter/nicehash/storage.go index 6ecf124..c4b9482 100644 --- a/splitter/nicehash/storage.go +++ b/splitter/nicehash/storage.go @@ -84,7 +84,7 @@ func (s *NonceStorage) Remove(miner *proxy.Miner) { // storage.SetJob(job) func (s *NonceStorage) SetJob(job proxy.Job) { s.mu.Lock() - if s.job.ClientID == job.ClientID || s.job.ClientID == "" { + if s.job.IsValid() && s.job.ClientID != "" && s.job.ClientID == job.ClientID { s.prevJob = s.job } else { s.prevJob = proxy.Job{} @@ -131,7 +131,7 @@ func (s *NonceStorage) JobForID(id string) (job proxy.Job, valid bool, expired b if id == s.job.JobID { return s.job, true, false } - if id == s.prevJob.JobID && id != "" { + if s.prevJob.IsValid() && s.prevJob.ClientID != "" && id == s.prevJob.JobID { return s.prevJob, true, true } return proxy.Job{}, false, false diff --git a/splitter/nicehash/storage_test.go b/splitter/nicehash/storage_test.go index b1aaaa3..1a4874f 100644 --- a/splitter/nicehash/storage_test.go +++ b/splitter/nicehash/storage_test.go @@ -62,6 +62,15 @@ func TestNonceStorage_IsValidJobID_Ugly(t *testing.T) { } } +func TestNonceStorage_IsValidJobID_BadClientID(t *testing.T) { + storage := NewNonceStorage() + storage.SetJob(proxy.Job{Blob: "abcd", JobID: "job-1", ClientID: "pool-a"}) + storage.SetJob(proxy.Job{Blob: "efgh", JobID: "job-2", ClientID: "pool-b"}) + if storage.IsValidJobID("job-1") { + t.Fatal("expected previous job ID from a different client to be invalid") + } +} + func TestNonceMapper_OnDisconnect_Ugly(t *testing.T) { mapper := NewNonceMapper(1, &proxy.Config{}, nil) mapper.pending[1] = SubmitContext{RequestID: 7} diff --git a/splitter/simple/mapper.go b/splitter/simple/mapper.go index 2af9a38..a073d8e 100644 --- a/splitter/simple/mapper.go +++ b/splitter/simple/mapper.go @@ -46,7 +46,7 @@ func (m *SimpleMapper) OnJob(job proxy.Job) { } m.mu.Lock() - if m.job.ClientID == job.ClientID || m.job.ClientID == "" { + if m.job.IsValid() && m.job.ClientID != "" && m.job.ClientID == job.ClientID { m.prevJob = m.job } else { m.prevJob = proxy.Job{} @@ -75,7 +75,7 @@ func (m *SimpleMapper) JobForID(id string) (proxy.Job, bool, bool) { if id == m.job.JobID { return m.job, true, false } - if id == m.prevJob.JobID { + if m.prevJob.IsValid() && m.prevJob.ClientID != "" && id == m.prevJob.JobID { return m.prevJob, true, true } return proxy.Job{}, false, false diff --git a/splitter/simple/splitter_test.go b/splitter/simple/splitter_test.go index 383a1ab..9ebf6a1 100644 --- a/splitter/simple/splitter_test.go +++ b/splitter/simple/splitter_test.go @@ -152,6 +152,18 @@ func TestSimpleMapper_OnResultAccepted_Good(t *testing.T) { } } +func TestSimpleMapper_JobForID_BadClientID(t *testing.T) { + mapper := &SimpleMapper{ + pending: make(map[int64]simpleSubmitContext), + } + mapper.OnJob(proxy.Job{Blob: strings.Repeat("1", 160), JobID: "job-a", ClientID: "pool-a"}) + mapper.OnJob(proxy.Job{Blob: strings.Repeat("0", 160), JobID: "job-b", ClientID: "pool-b"}) + + if valid, expired := mapper.JobStatus("job-a"); valid || expired { + t.Fatalf("expected stale job from a different client to be invalid, got valid=%t expired=%t", valid, expired) + } +} + func TestConfigWatcher_Start_Ugly(t *testing.T) { path := t.TempDir() + "/config.json" errorValue := os.WriteFile(path, []byte(`{"bind":[{"host":"127.0.0.1","port":3333}],"pools":[{"url":"pool-a:3333","enabled":true}]}`), 0o644)