channels_sv2: bound job-storage retention (future templates, past jobs, replaced group jobs) - #2290
Open
plebhash wants to merge 6 commits into
Open
Conversation
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)
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
force-pushed
the
2026-08-09-bound-job-storage-retention
branch
from
August 9, 2026 20:34
6211eb6 to
456fb81
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
close #2289
close https://github.com/project-loupe/audit-stratum/issues/101
close https://github.com/project-loupe/audit-stratum/issues/100
close https://github.com/project-loupe/audit-stratum/issues/97