diff options
Diffstat (limited to 'src/rpc.cpp')
| -rw-r--r-- | src/rpc.cpp | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/src/rpc.cpp b/src/rpc.cpp index f1a7153..23e25ef 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp | |||
| @@ -2484,6 +2484,26 @@ static const double VARDIFF_MAX = 1e12; | |||
| 2484 | static const int64 VARDIFF_STALL_SECS = 45; // 3x share target -- reacts faster without false-triggering on normal variance | 2484 | static const int64 VARDIFF_STALL_SECS = 45; // 3x share target -- reacts faster without false-triggering on normal variance |
| 2485 | static const double VARDIFF_STALL_CUT = 4.0; // divide difficulty by this much | 2485 | static const double VARDIFF_STALL_CUT = 4.0; // divide difficulty by this much |
| 2486 | 2486 | ||
| 2487 | // #7: m->hashRate is an EWMA sampled only when a share arrives, so a miner | ||
| 2488 | // that stops hashing keeps its last estimate forever and RefreshStats sums | ||
| 2489 | // it into the announced pool total for as long as the connection sits open | ||
| 2490 | // -- the published pool hashrate ran several times over ground truth | ||
| 2491 | // because of exactly this. The decay pass in PoolEventLoop applies this | ||
| 2492 | // policy: a miner gets a grace of HASHRATE_IDLE_MISSES expected share | ||
| 2493 | // intervals (expected interval = expected hashes per share at its current | ||
| 2494 | // difficulty / its last rate estimate) with no share, then its estimate | ||
| 2495 | // decays with a half-life of one more such interval, computed from | ||
| 2496 | // absolute time so the result does not depend on how often the loop ticks. | ||
| 2497 | // The interval is clamped to [HASHRATE_MIN_INTERVAL, HASHRATE_MAX_INTERVAL] | ||
| 2498 | // so a fast miner at the vardiff floor (expected interval of milliseconds) | ||
| 2499 | // is not punished for ordinary share-delivery jitter, and a very slow | ||
| 2500 | // miner's grace does not stretch past the point where its estimate means | ||
| 2501 | // anything. At the vardiff target of one share per 15s, a stopped miner's | ||
| 2502 | // announced rate is gone within minutes. | ||
| 2503 | static const double HASHRATE_IDLE_MISSES = 4.0; // grace, in expected share intervals | ||
| 2504 | static const double HASHRATE_MIN_INTERVAL = 1.0; // seconds; floor for the expected interval | ||
| 2505 | static const double HASHRATE_MAX_INTERVAL = 3600.0; // seconds; ceiling for the expected interval | ||
| 2506 | |||
| 2487 | struct Miner { | 2507 | struct Miner { |
| 2488 | btf_socket_t fd; | 2508 | btf_socket_t fd; |
| 2489 | bool authorised = false; | 2509 | bool authorised = false; |
| @@ -4900,6 +4920,26 @@ static void PoolEventLoop() | |||
| 4900 | } | 4920 | } |
| 4901 | } | 4921 | } |
| 4902 | 4922 | ||
| 4923 | // 3.6. Hashrate decay (#7) -- see the policy comment at | ||
| 4924 | // HASHRATE_IDLE_MISSES. The EWMA is only re-sampled on share arrival, | ||
| 4925 | // so without this pass a miner that stops hashing keeps its last | ||
| 4926 | // estimate forever and the summed pool hashrate RefreshStats (and | ||
| 4927 | // the nostr announcement built from it) publishes is fiction. | ||
| 4928 | for (Miner* m : gMiners) { | ||
| 4929 | if (m->hashRate <= 0.0 || m->lastShareTime <= 0) continue; | ||
| 4930 | double expected = ExpectedHashesForDifficulty(m->difficulty) / | ||
| 4931 | std::max(m->hashRate, 1e-9); | ||
| 4932 | if (expected < HASHRATE_MIN_INTERVAL) expected = HASHRATE_MIN_INTERVAL; | ||
| 4933 | if (expected > HASHRATE_MAX_INTERVAL) expected = HASHRATE_MAX_INTERVAL; | ||
| 4934 | double silent = (double)(GetTime() - m->lastShareTime); | ||
| 4935 | double grace = HASHRATE_IDLE_MISSES * expected; | ||
| 4936 | if (silent <= grace) continue; | ||
| 4937 | // Half-life of one expected interval past the grace period. | ||
| 4938 | // Written off absolute time, not per-tick, so the decay curve is | ||
| 4939 | // the same however often this loop runs. | ||
| 4940 | m->hashRate *= pow(0.5, (silent - grace) / expected); | ||
| 4941 | } | ||
| 4942 | |||
| 4903 | // 4. Select over miner sockets | 4943 | // 4. Select over miner sockets |
| 4904 | if (!gMiners.empty()) { | 4944 | if (!gMiners.empty()) { |
| 4905 | fd_set fds; FD_ZERO(&fds); | 4945 | fd_set fds; FD_ZERO(&fds); |