upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/fuzz_net_message.cpp
diff options
context:
space:
mode:
authorbitflash-maintainer <noreply@bitflash.invalid>2026-09-02 15:23:02 +0000
committerbitflash-maintainer <noreply@bitflash.invalid>2026-09-02 15:23:02 +0000
commit07051b2378734d62fb94a4a62819d8150452b661 (patch)
treeb20b912b18d5da1f524209bedda395d155fe11ef /src/fuzz_net_message.cpp
parentf5def7625e6369d117cc8f02b7c0244b70d6f779 (diff)
pool: compute a miner's faded hashrate instead of decaying it in place
2bca62a decayed m->hashRate from the event loop's miner sweep, which turned a figure that is only ever displayed into an accumulator, and got the curve wrong at both ends. Each pass recomputed `expected` -- and so `grace` -- from the estimate it had just decayed. Every decay raised `expected`, which raised the grace that gates the next decay, so `grace` chased `silent` upward and the reported rate settled into a 1/t crawl instead of the half-life the commit's own comment documents: 291x too high at ten half-lives past the grace, and still announcing 0.4% of baseline four hours into a silence. #7 is about the pool over-reporting its hashrate, and this under-corrected it for hours. The far end was worse. Once `expected` reached HASHRATE_MAX_INTERVAL it could not rise any further, the feedback that had been gating each pass was gone, and the decay did begin to compound -- once a second, against the total elapsed silence, because lastShareTime does not advance while a miner is quiet and nothing recorded when the decay had last run. A miner four hours silent fell from 0.4% of its baseline to 1e-11 of it over the next hundred seconds, with nothing in the code or the announced number to explain the cliff. Neither behaviour is worth tuning, so drop the sweep. hashRate is read in exactly one place -- RefreshStats, building the per-worker rows and the total that the pool status and the nostr announcement publish -- and vardiff retargets from share timing alone and never reads it. So leave the stored value as the sample it always was and have RefreshStats ask MinerReportedHashRate() what to publish: a pure function of that sample and the absolute silence since the last share. With no stored decay state there is nothing for a tick rate, a missed pass or a repeated pass to perturb, and the answer is bit-identical from 1/60 Hz to 1000 Hz because nothing accumulates, not because the arithmetic was written carefully. It also keeps the fade out of the estimator: the EWMA on the share path still blends against the value it last computed rather than a faded copy of it, so a miner that resumes recovers exactly as it did before any of this, and there is no decay timestamp for a newly accepted or newly authorised connection to be caught holding unset. RefreshStats takes one GetTime() for the whole sweep, so the rows and the total they are summed into describe a single instant rather than a smear across it. The clamp is written !(expected > MIN) so a NaN lands on the floor instead of sailing through; a negative `silent` from a clock stepping backwards reports the sample unchanged rather than scaling it up; and past HASHRATE_DECAY_CUTOFF half-lives the answer is a flat zero rather than pow() walking down into the denormals. This also drops the std::max(m->hashRate, 1e-9) the old pass carried, which the `hashRate <= 0.0` guard immediately above it had already made dead. pool-stratum gains ten checks over the policy: the full estimate inside the grace, a thousand samples at one instant returning one value and leaving the estimate untouched, a few percent lost one second past the grace rather than the whole estimate, exactly half at one expected interval past it, zero after an hour of silence, no inflation from a backwards clock, zero for a miner that has no rate sample yet, and nothing non-finite anywhere across a long silence.
Diffstat (limited to 'src/fuzz_net_message.cpp')
0 files changed, 0 insertions, 0 deletions