Skip to content

channels_sv2: bound job-storage retention (future templates, past jobs, replaced group jobs) - #2290

Open
plebhash wants to merge 6 commits into
stratum-mining:mainfrom
plebhash:2026-08-09-bound-job-storage-retention
Open

channels_sv2: bound job-storage retention (future templates, past jobs, replaced group jobs)#2290
plebhash wants to merge 6 commits into
stratum-mining:mainfrom
plebhash:2026-08-09-bound-job-storage-retention

Conversation

@plebhash

@plebhash plebhash commented Aug 9, 2026

Copy link
Copy Markdown
Member

@plebhash plebhash changed the title channels_sv2: improve bound job-storage retention (future templates, past jobs, replaced group jobs) channels_sv2: bound job-storage retention (future templates, past jobs, replaced group jobs) Aug 9, 2026
JobStore::add_future_job retained every future template's full job keyed
by the peer-controlled template_id. A malicious or compromised Template
Distribution peer could stream future templates while withholding
SetNewPrevHash, growing future_jobs and future_template_to_job_id
without limit, with each entry carrying large wire-controlled buffers.

Track template IDs in receipt order and evict the oldest future job
beyond MAX_FUTURE_JOBS (16), the same pattern used for client channels.
One change covers all three server channel types (group, standard,
extended), which all route future templates through add_future_job.

Eviction deliberately does not prune retired extranonce prefixes: a
prefix referenced only by an evicted job is held until the next tip
transition, which is the safe direction (slot reserved longer, never
released early).
Group channels never validate shares (the module docs explicitly say
they don't track past or stale jobs), yet they retained job history at
two sites: for every non-future template, GroupChannel::on_new_template
routed through JobStore::add_active_job, which moves the previous
active job into the unbounded past_jobs map, and future-job activation
retired the displaced active job the same way, leaving one stale entry
per tip transition. The former was pure unbounded retention: a
malicious Template Distribution peer could establish a chain tip and
then stream immediately-active templates while withholding
SetNewPrevHash, retaining one full job per message.

Add JobStore::replace_active_job and
JobStore::activate_future_job_replacing_active, which drop the
displaced active job instead of retaining it, and use them in the group
channel so it keeps no past or stale job history at all.
Standard and extended server channels grow past_jobs through
JobStore::add_active_job (non-future templates and SetCustomMiningJob),
cleared only on activation. A malicious Template Distribution peer can
stream non-future templates while withholding SetNewPrevHash, retaining
one full job per message without limit.

Unlike group channels, these channels validate shares against past
jobs, so the history is bounded instead of dropped: track job IDs in
retirement order and evict the oldest past job beyond MAX_PAST_JOBS
(16). A share against an evicted job degrades to InvalidJobId instead
of Stale, acceptable within a single tip window. stale_jobs is
transitively bounded, since it is only ever a snapshot of past_jobs at
tip transitions.
Client channels retain past jobs for late-share validation, but the
job stream is upstream-controlled, so the collection must be bounded
to prevent memory exhaustion. Introduce a dedicated cap, separate from
MAX_FUTURE_JOBS, to be enforced by the standard and extended client
channels.
A malicious upstream can stream immediately-active jobs (min_ntime
present) on one channel and force one retained past job per message,
no proof of work required, since past_jobs was only cleared on a
successful SetNewPrevHash the attacker can withhold.

Track past job IDs in retirement order and evict the oldest beyond
MAX_PAST_JOBS, mirroring the future-job bound. A share against an
evicted job degrades to InvalidJobId instead of Stale, acceptable
within a single tip window. stale_jobs is transitively bounded, since
it is only ever a snapshot of past_jobs at tip transitions.
Same defect as the standard client channel, at three sites: a
malicious upstream can grow past_jobs without limit through
immediately-active NewExtendedMiningJob messages,
SetCustomMiningJobSuccess, or the job displaced on chain tip
transitions, since the map was only cleared on a successful
SetNewPrevHash (or chain tip update) the attacker can withhold.

Route all four insertion sites through a shared helper that tracks
past job IDs in retirement order and evicts the oldest beyond
MAX_PAST_JOBS. A share against an evicted job degrades to InvalidJobId
instead of Stale, acceptable within a single tip window.
@plebhash
plebhash force-pushed the 2026-08-09-bound-job-storage-retention branch from 6211eb6 to 456fb81 Compare August 9, 2026 20:34
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.

channels_sv2: need to bound job-storage retention (future templates, past jobs, replaced group jobs)

1 participant