diff --git a/core_impl.go b/core_impl.go index e9e4a5c..48bf54a 100644 --- a/core_impl.go +++ b/core_impl.go @@ -203,6 +203,14 @@ func targetFromDifficulty(diff uint64) string { return hex.EncodeToString(raw[:]) } +func EffectiveShareDifficulty(job Job, miner *Miner) uint64 { + diff := job.DifficultyFromTarget() + if miner == nil || miner.customDiff == 0 || diff == 0 || diff <= miner.customDiff { + return diff + } + return miner.customDiff +} + // NewCustomDiff creates a login-time custom difficulty resolver. // // resolver := proxy.NewCustomDiff(50000) diff --git a/customdiff_test.go b/customdiff_test.go index 610bff0..220b7ee 100644 --- a/customdiff_test.go +++ b/customdiff_test.go @@ -28,3 +28,12 @@ func TestCustomDiff_OnLogin(t *testing.T) { t.Fatalf("expected global diff fallback, got %d", miner.customDiff) } } + +func TestEffectiveShareDifficulty_CustomDiffCapsPoolDifficulty(t *testing.T) { + job := Job{Target: "b88d0600"} + miner := &Miner{customDiff: 25000} + + if got := EffectiveShareDifficulty(job, miner); got != 25000 { + t.Fatalf("expected capped difficulty 25000, got %d", got) + } +} diff --git a/splitter/nicehash/impl.go b/splitter/nicehash/impl.go index 09d2b13..2ab2342 100644 --- a/splitter/nicehash/impl.go +++ b/splitter/nicehash/impl.go @@ -291,6 +291,7 @@ func (m *NonceMapper) Submit(event *proxy.SubmitEvent) { RequestID: event.RequestID, MinerID: event.Miner.ID(), JobID: jobID, + Diff: proxy.EffectiveShareDifficulty(job, event.Miner), StartedAt: time.Now(), } m.lastUsed = time.Now() @@ -359,13 +360,13 @@ func (m *NonceMapper) OnResultAccepted(sequence int64, accepted bool, errorMessa if accepted { miner.Success(ctx.RequestID, "OK") if m.events != nil { - m.events.Dispatch(proxy.Event{Type: proxy.EventAccept, Miner: miner, Job: &job, Diff: job.DifficultyFromTarget(), Latency: latency, Expired: expired}) + m.events.Dispatch(proxy.Event{Type: proxy.EventAccept, Miner: miner, Job: &job, Diff: ctx.Diff, Latency: latency, Expired: expired}) } return } miner.ReplyWithError(ctx.RequestID, errorMessage) if m.events != nil { - m.events.Dispatch(proxy.Event{Type: proxy.EventReject, Miner: miner, Job: &job, Diff: job.DifficultyFromTarget(), Error: errorMessage, Latency: latency}) + m.events.Dispatch(proxy.Event{Type: proxy.EventReject, Miner: miner, Job: &job, Diff: ctx.Diff, Error: errorMessage, Latency: latency}) } } diff --git a/splitter/nicehash/mapper.go b/splitter/nicehash/mapper.go index fa192fd..3197e6c 100644 --- a/splitter/nicehash/mapper.go +++ b/splitter/nicehash/mapper.go @@ -34,5 +34,6 @@ type SubmitContext struct { RequestID int64 // JSON-RPC id from the miner's submit request MinerID int64 // miner that submitted JobID string + Diff uint64 StartedAt time.Time } diff --git a/splitter/nicehash/mapper_start_test.go b/splitter/nicehash/mapper_start_test.go index cb8eb96..c9f128b 100644 --- a/splitter/nicehash/mapper_start_test.go +++ b/splitter/nicehash/mapper_start_test.go @@ -165,3 +165,36 @@ func TestMapper_OnResultAccepted_ExpiredUsesPreviousJob(t *testing.T) { t.Fatal("expected accept event") } } + +func TestMapper_OnResultAccepted_CustomDiffUsesEffectiveDifficulty(t *testing.T) { + bus := proxy.NewEventBus() + events := make(chan proxy.Event, 1) + bus.Subscribe(proxy.EventAccept, func(e proxy.Event) { + events <- e + }) + + miner := proxy.NewMiner(discardConn{}, 3333, nil) + miner.SetID(8) + mapper := NewNonceMapper(1, &proxy.Config{}, &startCountingStrategy{}) + mapper.events = bus + mapper.storage.job = proxy.Job{JobID: "job-new", Blob: "blob-new", Target: "b88d0600"} + mapper.storage.miners[miner.ID()] = miner + mapper.pending[10] = SubmitContext{ + RequestID: 77, + MinerID: miner.ID(), + JobID: "job-new", + Diff: 25000, + StartedAt: time.Now(), + } + + mapper.OnResultAccepted(10, true, "") + + select { + case event := <-events: + if event.Diff != 25000 { + t.Fatalf("expected effective difficulty 25000, got %d", event.Diff) + } + case <-time.After(time.Second): + t.Fatal("expected accept event") + } +} diff --git a/splitter/simple/impl.go b/splitter/simple/impl.go index 536272e..ad0597f 100644 --- a/splitter/simple/impl.go +++ b/splitter/simple/impl.go @@ -272,8 +272,17 @@ func (m *SimpleMapper) Submit(event *proxy.SubmitEvent) { m.rejectInvalidJobLocked(event, m.currentJob) return } + submissionJob := m.currentJob + if jobID == m.prevJob.JobID && m.prevJob.JobID != "" { + submissionJob = m.prevJob + } seq := m.strategy.Submit(jobID, event.Nonce, event.Result, event.Algo) - m.pending[seq] = submitContext{RequestID: event.RequestID, StartedAt: time.Now(), JobID: jobID} + m.pending[seq] = submitContext{ + RequestID: event.RequestID, + Diff: proxy.EffectiveShareDifficulty(submissionJob, event.Miner), + StartedAt: time.Now(), + JobID: jobID, + } } func (m *SimpleMapper) rejectInvalidJobLocked(event *proxy.SubmitEvent, job proxy.Job) { @@ -338,13 +347,13 @@ func (m *SimpleMapper) OnResultAccepted(sequence int64, accepted bool, errorMess if accepted { miner.Success(ctx.RequestID, "OK") if m.events != nil { - m.events.Dispatch(proxy.Event{Type: proxy.EventAccept, Miner: miner, Diff: job.DifficultyFromTarget(), Job: &job, Latency: latency, Expired: expired}) + m.events.Dispatch(proxy.Event{Type: proxy.EventAccept, Miner: miner, Diff: ctx.Diff, Job: &job, Latency: latency, Expired: expired}) } return } miner.ReplyWithError(ctx.RequestID, errorMessage) if m.events != nil { - m.events.Dispatch(proxy.Event{Type: proxy.EventReject, Miner: miner, Diff: job.DifficultyFromTarget(), Job: &job, Error: errorMessage, Latency: latency}) + m.events.Dispatch(proxy.Event{Type: proxy.EventReject, Miner: miner, Diff: ctx.Diff, Job: &job, Error: errorMessage, Latency: latency}) } } diff --git a/splitter/simple/impl_test.go b/splitter/simple/impl_test.go index 2ce5f89..c24f70b 100644 --- a/splitter/simple/impl_test.go +++ b/splitter/simple/impl_test.go @@ -184,6 +184,45 @@ func TestSimpleMapper_OnResultAccepted_Expired(t *testing.T) { } } +func TestSimpleMapper_OnResultAccepted_CustomDiffUsesEffectiveDifficulty(t *testing.T) { + bus := proxy.NewEventBus() + events := make(chan proxy.Event, 1) + var once sync.Once + bus.Subscribe(proxy.EventAccept, func(e proxy.Event) { + once.Do(func() { + events <- e + }) + }) + + miner := proxy.NewMiner(discardConn{}, 3333, nil) + miner.SetID(2) + job := proxy.Job{JobID: "job-new", Blob: "blob-new", Target: "b88d0600"} + mapper := &SimpleMapper{ + miner: miner, + currentJob: job, + events: bus, + pending: map[int64]submitContext{ + 8: { + RequestID: 10, + Diff: 25000, + StartedAt: time.Now(), + JobID: "job-new", + }, + }, + } + + mapper.OnResultAccepted(8, true, "") + + select { + case event := <-events: + if event.Diff != 25000 { + t.Fatalf("expected effective difficulty 25000, got %d", event.Diff) + } + case <-time.After(time.Second): + t.Fatal("expected accept event") + } +} + func TestSimpleMapper_Submit_InvalidJob_Good(t *testing.T) { minerConn, clientConn := net.Pipe() defer minerConn.Close() diff --git a/splitter/simple/mapper.go b/splitter/simple/mapper.go index 3fd4f2b..1a321d2 100644 --- a/splitter/simple/mapper.go +++ b/splitter/simple/mapper.go @@ -28,6 +28,7 @@ type SimpleMapper struct { type submitContext struct { RequestID int64 + Diff uint64 StartedAt time.Time JobID string }