diff options
| author | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-02 05:42:17 +0000 |
|---|---|---|
| committer | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-02 05:42:17 +0000 |
| commit | d7b1e8a1d54192df2fcf633fbcdffb43389ff8e2 (patch) | |
| tree | c65b2390f4fef2d99c09579e7544387a65cf4f69 | |
| parent | e4f898c4a6b9900553c64b9804889b5fdae3e55f (diff) | |
pool: guard the share-target floor where the old cap branch was dead
ShareTargetFromDifficulty ended with
if (t < diff1 && difficulty < 1.0) t = ~uint256(0);
which can never fire: t = diff1/difficulty, so difficulty < 1.0 implies
t > diff1 and the two conditions exclude each other. The branch was
reaching for a real hazard, though, so say the hazard directly instead
of deleting the guard: diff1 is ~uint256(0) >> 12, a hair under 2^244,
so the true share target stops fitting in a uint256 once difficulty
reaches 2^-12 (1/4096), and the fixed-point divisor
(uint64)(difficulty * 65536.0) truncates to zero -- a division by zero
-- for any difficulty under 2^-16. Past the first threshold
getuint256() would return the low 256 bits of an oversized quotient, a
wrapped target that is arbitrarily HARDER than difficulty 1. Both
thresholds sit far below VARDIFF_MIN (0.001), so nothing live comes
near this; the guard exists for any caller that bypasses vardiff. At
those difficulties every hash is meant to be a share, so return
all-ones, the easiest representable target. Boundary verified
numerically against the exact fixed-point algorithm: at difficulty
exactly 1/4096 the quotient is 2^256 - 4096 (fits), one ulp below it
overflows, and below 2^-16 the divisor is zero.
Closes #11
| -rw-r--r-- | src/rpc.cpp | 21 |
1 files changed, 17 insertions, 4 deletions
diff --git a/src/rpc.cpp b/src/rpc.cpp index a4b53ca..82f895b 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp | |||
| @@ -115,15 +115,28 @@ static uint256 ShareTargetFromDifficulty(double difficulty) | |||
| 115 | { | 115 | { |
| 116 | if (difficulty <= 0.0) difficulty = 1.0; | 116 | if (difficulty <= 0.0) difficulty = 1.0; |
| 117 | static const uint256 diff1 = CBigNum(bnProofOfWorkLimit).getuint256(); | 117 | static const uint256 diff1 = CBigNum(bnProofOfWorkLimit).getuint256(); |
| 118 | // Representability floor. shareTarget = diff1 / difficulty, and diff1 is | ||
| 119 | // ~uint256(0) >> 12, i.e. a hair under 2^244 -- so the true target stops | ||
| 120 | // fitting in a uint256 once difficulty reaches 2^-12 (= 1/4096), and the | ||
| 121 | // fixed-point divide below breaks even earlier in a second way: the | ||
| 122 | // (uint64)(difficulty * 65536.0) divisor truncates to zero for any | ||
| 123 | // difficulty under 2^-16. Both thresholds sit far below VARDIFF_MIN | ||
| 124 | // (0.001), so live operation never comes near this, but a caller that | ||
| 125 | // bypasses vardiff (or a future VARDIFF_MIN) must not divide by zero or | ||
| 126 | // hand back getuint256()'s low-256-bit truncation of an oversized | ||
| 127 | // quotient -- a wrapped target is not merely wrong, it is arbitrarily | ||
| 128 | // HARDER than difficulty 1. At these difficulties every hash is meant to | ||
| 129 | // be a share, so the honest answer is the easiest representable target. | ||
| 130 | // (This replaces a dead branch that read `if (t < diff1 && difficulty < | ||
| 131 | // 1.0)`: t = diff1/difficulty, so difficulty < 1.0 implies t > diff1 and | ||
| 132 | // the two conditions could never both hold.) | ||
| 133 | if (difficulty < 1.0 / 4096.0) return ~uint256(0); | ||
| 118 | // shareTarget = diff1 / difficulty | 134 | // shareTarget = diff1 / difficulty |
| 119 | CBigNum bn; bn.setuint256(diff1); | 135 | CBigNum bn; bn.setuint256(diff1); |
| 120 | // Multiply by 2^16 to keep precision, divide, shift back | 136 | // Multiply by 2^16 to keep precision, divide, shift back |
| 121 | bn <<= 16; | 137 | bn <<= 16; |
| 122 | bn /= (uint64)(difficulty * 65536.0); | 138 | bn /= (uint64)(difficulty * 65536.0); |
| 123 | uint256 t = bn.getuint256(); | 139 | return bn.getuint256(); |
| 124 | // Cap at all-ones (maximum, easiest possible) | ||
| 125 | if (t < diff1 && difficulty < 1.0) t = ~uint256(0); | ||
| 126 | return t; | ||
| 127 | } | 140 | } |
| 128 | 141 | ||
| 129 | // Expected number of hashes to find one share at a given Stratum difficulty, | 142 | // Expected number of hashes to find one share at a given Stratum difficulty, |