Skip to content

Widen the job retention window from ~60s to ~300s - #72

Merged
rsantacroce merged 1 commit into
LayerTwo-Labs:mainfrom
Wired4ncer:up/job-retention-window
Sep 1, 2026
Merged

Widen the job retention window from ~60s to ~300s#72
rsantacroce merged 1 commit into
LayerTwo-Labs:mainfrom
Wired4ncer:up/job-retention-window

Conversation

@Wired4ncer

Copy link
Copy Markdown
Contributor

Jobs stop being solvable about 60 seconds after they are issued. Any miner with a hop in front of it — a proxy, rented hashrate — has its shares rejected as stale here while other pools accept them. ckpool's equivalent limit is 600s.

Measured on a production pool before proposing this. Over 16 hours of instrumented rejects, every stale rejection was for a job under 300s old, and the two worst-hit miners were running 11% and 39% rejects against a pool-wide 0.44%. After moving to a 300s window: pool-wide 0.05%, zero evictions in the next hour where ~350 were expected, and the 11% miner went to 0%.

Three changes, and the middle one is why this isn't a one-liner:

RECENT_JOB_TTL_MS  60000 -> 300000
RECENT_JOBS            8 -> 16      (so the ring stays slack, not binding)
JOB_DIFF_RING         16 -> derived from RECENT_JOBS

JOB_DIFF_RING was a literal 16 sized against a ring of 8. Raising the ring alone would leave the oldest still-solvable job with no difficulty entry, so a correct submit would be judged at the wrong difficulty — a silent wrong answer rather than a build error. It is now derived, and a _Static_assert ties ring depth to the TTL so raising one without the other fails the build. Verified by shrinking the ring and watching the build break.

One test needed updating: test_job_survives_retirement_while_held pushed a hardcoded 24 jobs to force ring turnover, sized against a ring of 8. At 16 that margin drops to 1.5x, so it is raised to 64 with a comment saying why.

A job stops being solvable about 60 seconds after it is issued, and the
retention ring never gets a say. RECENT_JOBS is 8, which at the default
30s bitcoind_poll_interval_ms is 240s of capacity -- but RECENT_JOB_TTL_MS
expires everything at 60s first, so the ring never binds and its slots are
dead capacity. The comment above JOB_DIFF_RING describes retention the code
does not actually have.

That makes the effective window ~60-90s (60s plus the wait for the next
job, since retire_job's sweep is lazy). ckpool's equivalent cap is 600s.
So any miner whose work arrives slightly late -- a proxy, rented hashrate,
anything with a hop in front of it -- gets its shares rejected as stale
here and accepted everywhere else.

Measured on a production pool before proposing this: over 16 hours of
instrumented rejects, every stale rejection was for a job under 300s old,
and the two worst-affected miners were running 11% and 39% rejects against
a pool-wide 0.44%. After deploying a 300s window: pool-wide 0.05%, zero
evictions in the following hour where ~350 were expected, and the 11%
miner went to 0% across 654 shares.

Three changes, and the second is why this is not a one-line patch:

  RECENT_JOB_TTL_MS  60000 -> 300000
  RECENT_JOBS            8 -> 16      (so the ring stays slack, not binding)
  JOB_DIFF_RING         16 -> derived from RECENT_JOBS

JOB_DIFF_RING was a literal 16 sized against a ring of 8. Raising the ring
alone would leave the oldest still-solvable job with no difficulty entry,
so a correct submit would be judged at the wrong difficulty -- a silent
wrong answer rather than a build error. It is now derived.

A _Static_assert ties the ring depth to the TTL so raising one without the
other fails the build. Verified by shrinking the ring and watching the
build break, not by assuming.

test_job_survives_retirement_while_held pushed a hardcoded 24 jobs to force
ring turnover, sized against a ring of 8. With the ring at 16 that margin
falls to 1.5x, so it is raised to 64 and carries a comment saying it must
stay ahead of RECENT_JOBS -- which is not visible from the test, so it
cannot be derived.

NOT included: marking shares stale when they predate a tip change, as
ckpool does (workbase_id < blockchange_id) while keeping every same-height
job valid regardless of age. That is arguably the better shape, but it
would newly REFUSE shares that are credited today, at block boundaries, to
exactly the miners this change is meant to help. It deserves its own
change and its own evidence.
@rsantacroce
rsantacroce merged commit ad30083 into LayerTwo-Labs:main Sep 1, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants