Use effective custom diff in share accounting

This commit is contained in:
Virgil 2026-04-05 00:32:43 +00:00
parent 9d2b1f368c
commit 55d44df9c2
8 changed files with 106 additions and 5 deletions

View file

@ -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)

View file

@ -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)
}
}

View file

@ -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})
}
}

View file

@ -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
}

View file

@ -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")
}
}

View file

@ -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})
}
}

View file

@ -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()

View file

@ -28,6 +28,7 @@ type SimpleMapper struct {
type submitContext struct {
RequestID int64
Diff uint64
StartedAt time.Time
JobID string
}