Skip to content

channels_sv2: clamp target to max_target instead of erroring#2118

Merged
plebhash merged 5 commits intostratum-mining:mainfrom
vnprc:channels-sv2/clamp-max-target
Apr 22, 2026
Merged

channels_sv2: clamp target to max_target instead of erroring#2118
plebhash merged 5 commits intostratum-mining:mainfrom
vnprc:channels-sv2/clamp-max-target

Conversation

@vnprc
Copy link
Copy Markdown
Contributor

@vnprc vnprc commented Mar 16, 2026

Problem

When a pool's vardiff computes a target easier than the client's declared
max_target, update_channel() returns Err(RequestedMaxTargetOutOfRange).
This silently breaks vardiff for the affected channel: the error is swallowed by
the caller, no difficulty update is applied, and the miner is permanently stuck
at its last successfully-set difficulty. The pool logs a WARN roughly every
60 seconds per affected channel while mining continues at the wrong difficulty.

This is not a hypothetical edge case. It triggers reliably for low-hashrate
miners whose natural vardiff target overshoots their declared max_target.

Root Cause

The max_target field in OpenExtendedMiningChannel means "the easiest
difficulty I will accept."
When vardiff computes a target easier than
max_target, the correct response is to assign exactly max_target — the
client has already declared that difficulty acceptable. The current code errors
instead, which is both incorrect per the spec and operationally harmful.

Fix

Replace the RequestedMaxTargetOutOfRange error path with a clamp in four
places:

  • ExtendedChannel::new() — channel creation
  • ExtendedChannel::update_channel() — vardiff updates
  • StandardChannel::new() — channel creation
  • StandardChannel::update_channel() — vardiff updates

Also removes two stray println! debug statements from ExtendedChannel::new().

Tests

The existing test_update_channel tests in both extended.rs and standard.rs
already exercise this path (very_small_hashrate = 0.1). They previously
asserted is_err() / RequestedMaxTargetOutOfRange. They now assert is_ok()
and verify the channel target was clamped to not_so_permissive_max_target.
All 50 unit tests pass.

Notes

  • RequestedMaxTargetOutOfRange is preserved in both error enums — it remains
    reachable from the UpdateChannel message handler path where the client itself
    sends a bad max_target.
  • No API surface changes (no new public types, no signature changes).

Pre-existing CI failure

cargo clippy currently fails on upstream main due to needless_lifetimes in
binary_sv2 — unrelated to this PR.


companion stratum-mining/sv2-apps#447

@Alkamal01
Copy link
Copy Markdown

Tested this locally and the math checks out. Moving from an error to a clamp in update_channel is the right move for vardiff—it stops the lock-up for smaller miners without touching the high-end.

I did a quick check on the f64 limits too. Since the clamp is unidirectional (target>max_target), it won't trigger for high-hashrate ASICs, so no new precision loss there. Also, good call on dropping those println! calls in the constructor; we don't need the I/O lag in high-concurrency.

All 50 channels_sv2 tests passed. Concept is solid. LGTM.

@vnprc vnprc force-pushed the channels-sv2/clamp-max-target branch 2 times, most recently from 9e22e68 to 785ea6c Compare April 13, 2026 17:19
@vnprc
Copy link
Copy Markdown
Contributor Author

vnprc commented Apr 13, 2026

Thanks for looking at this @Alkamal01!

@plebhash
Copy link
Copy Markdown
Member

thanks for spotting this @vnprc

apologies for taking so long to review it, this is a great improvement!

overall the PR is pretty solid, but there's a few things left... I'm taking the liberty of implementing them to make the review cycles a bit more agile, can you rebase against main and cherry pick these commits from my fork here?

plebhash added a commit to vnprc/stratum that referenced this pull request Apr 21, 2026
…tended,standard}

to protect against constructor regressions with the changes introduced in stratum-mining#2118
plebhash added a commit to vnprc/stratum that referenced this pull request Apr 21, 2026
…_channel

to accurately describe the behavior introduced via stratum-mining#2118
plebhash added a commit to vnprc/stratum that referenced this pull request Apr 21, 2026
…tended,standard}

to protect against constructor regressions with the changes introduced in stratum-mining#2118
plebhash added a commit to vnprc/stratum that referenced this pull request Apr 21, 2026
…_channel

to accurately describe the behavior introduced via stratum-mining#2118
@plebhash plebhash force-pushed the channels-sv2/clamp-max-target branch from 19b6c86 to e834da2 Compare April 21, 2026 21:28
@plebhash
Copy link
Copy Markdown
Member

plebhash commented Apr 21, 2026

can you rebase against main and cherry pick these commits from my fork here?

actually nevermind @vnprc , I just realized I'm able to push here

Comment thread sv2/channels-sv2/src/server/extended.rs Outdated
Comment thread sv2/channels-sv2/src/server/extended.rs Outdated
Comment thread sv2/channels-sv2/src/server/standard.rs Outdated
Comment thread sv2/channels-sv2/src/server/standard.rs Outdated
vnprc and others added 5 commits April 22, 2026 09:39
When a pool's vardiff computes a target easier than the client's declared
max_target, update_channel() returned Err(RequestedMaxTargetOutOfRange).
This silently broke vardiff: once triggered, no further difficulty
adjustments succeeded for that channel. The pool logged a WARN every
~60s per affected channel while the miner stayed stuck at its last
successfully-set difficulty.

The max_target field in OpenExtendedMiningChannel means "the easiest
difficulty I will accept." If the pool's calculation produces something
easier, the correct response is to assign exactly max_target — not to
error. The client explicitly declared this difficulty acceptable.

Apply the same clamping logic to both ExtendedChannel and StandardChannel,
in both new() (channel creation) and update_channel() (vardiff updates).
Update the corresponding tests to assert clamping behavior rather than
expecting an error. Also remove two stray println! debug statements from
ExtendedChannel::new().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tended,standard}

to protect against constructor regressions with the changes introduced in stratum-mining#2118
…_channel

to accurately describe the behavior introduced via stratum-mining#2118
…2::server::error::{ExtendedChannelError,StandardChannelError}
@plebhash plebhash force-pushed the channels-sv2/clamp-max-target branch from 5effe04 to ae3741d Compare April 22, 2026 12:39
@vnprc
Copy link
Copy Markdown
Contributor Author

vnprc commented Apr 22, 2026

awesome! thanks for looking at it! lmk if i can help in any way.

@plebhash plebhash merged commit 6731ba5 into stratum-mining:main Apr 22, 2026
14 checks passed
plebhash added a commit to stratum-mining/sv2-apps that referenced this pull request Apr 22, 2026
plebhash added a commit to stratum-mining/sv2-apps that referenced this pull request Apr 22, 2026
plebhash added a commit to plebhash/sv2-uniffi that referenced this pull request Apr 23, 2026
plebhash added a commit to plebhash/sv2-uniffi that referenced this pull request Apr 23, 2026
plebhash added a commit to plebhash/sv2-uniffi that referenced this pull request Apr 24, 2026
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.

4 participants