upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/rpc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpc.cpp')
-rw-r--r--src/rpc.cpp38
1 files changed, 38 insertions, 0 deletions
diff --git a/src/rpc.cpp b/src/rpc.cpp
index 82f895b..f1a7153 100644
--- a/src/rpc.cpp
+++ b/src/rpc.cpp
@@ -2511,6 +2511,16 @@ struct Miner {
2511 int64 lastShareTime = 0; // GetTime() of the previous accepted share 2511 int64 lastShareTime = 0; // GetTime() of the previous accepted share
2512 double hashRate = 0.0; // smoothed H/s estimate 2512 double hashRate = 0.0; // smoothed H/s estimate
2513 2513
2514 // Replay guard for mining.submit (#8): nonces already credited on this
2515 // connection for the job it is currently working. Keyed to the job id in
2516 // seenNoncesJob and cleared by SendJob whenever that id changes, so a
2517 // resubmission under a NEW job is never turned away, while a replayed
2518 // (job_id, nonce) pair under the same job is refused before it can be
2519 // credited twice into roundShareCount -- the figure the payout split
2520 // divides by.
2521 std::set<uint32_t> seenNonces;
2522 std::string seenNoncesJob;
2523
2514 explicit Miner(btf_socket_t f) 2524 explicit Miner(btf_socket_t f)
2515 : fd(f), connectTime(GetTime()), 2525 : fd(f), connectTime(GetTime()),
2516 extranonce2(gNextExtranonce2.fetch_add(1)) {} 2526 extranonce2(gNextExtranonce2.fetch_add(1)) {}
@@ -2693,6 +2703,17 @@ static json MakeNotifyParams(const StratumJob& job, const CBlock& b,
2693static void SendJob(Miner* m, bool clean) 2703static void SendJob(Miner* m, bool clean)
2694{ 2704{
2695 if (!gHaveJob) return; 2705 if (!gHaveJob) return;
2706 // Every path that hands a miner a new job funnels through here, so this
2707 // is the one place the replay guard needs to follow the job id: nonces
2708 // credited under the previous job mean nothing under the new one. Keying
2709 // the clear to the id (rather than clearing unconditionally) keeps a
2710 // same-job re-notify -- the vardiff retarget and stall watchdog both
2711 // re-send the CURRENT job -- from reopening the duplicate window it
2712 // exists to close.
2713 if (m->seenNoncesJob != gCurrentJob.jobId) {
2714 m->seenNonces.clear();
2715 m->seenNoncesJob = gCurrentJob.jobId;
2716 }
2696 CBlock mb = BuildMinerBlock(gCurrentJob, m->extranonce2); 2717 CBlock mb = BuildMinerBlock(gCurrentJob, m->extranonce2);
2697 // Use this miner's own shareTarget (set by vardiff) in the notify params. 2718 // Use this miner's own shareTarget (set by vardiff) in the notify params.
2698 // The participant miner reads p[3] as its share target, and HandleLine 2719 // The participant miner reads p[3] as its share target, and HandleLine
@@ -2951,6 +2972,22 @@ static bool HandleLine(Miner* m, const std::string& rawLine,
2951 } 2972 }
2952 unsigned int nNonce; memcpy(&nNonce, nb.data(), 4); 2973 unsigned int nNonce; memcpy(&nNonce, nb.data(), 4);
2953 2974
2975 // Reject a replayed (job, nonce) before it costs a rebuild and a
2976 // RandomX hash: nothing about the work below distinguishes a second
2977 // submission of a valid share from the first, so without this check
2978 // it passes every test and is credited again -- and roundShareCount
2979 // is what the payout split divides by, so each replay multiplies the
2980 // address's cut of the round. The set is per-connection and cleared
2981 // by SendJob on every job change, so only a same-job repeat is
2982 // refused.
2983 if (m->seenNonces.count(nNonce)) {
2984 LogPrint("worker", "[worker->pool] duplicate share from %s"
2985 " nonce=%u job=%s -- already credited, not counting again\n",
2986 m->address.c_str(), nNonce, submitJobId.c_str());
2987 reply(false, "Duplicate share");
2988 return true;
2989 }
2990
2954 // Rebuild this miner's exact block (unique merkle via extranonce2) 2991 // Rebuild this miner's exact block (unique merkle via extranonce2)
2955 CBlock b = BuildMinerBlock(gCurrentJob, m->extranonce2); 2992 CBlock b = BuildMinerBlock(gCurrentJob, m->extranonce2);
2956 b.nNonce = nNonce; 2993 b.nNonce = nNonce;
@@ -2978,6 +3015,7 @@ static bool HandleLine(Miner* m, const std::string& rawLine,
2978 m->roundShares++; 3015 m->roundShares++;
2979 m->totalShares++; 3016 m->totalShares++;
2980 m->vardiffShares++; 3017 m->vardiffShares++;
3018 m->seenNonces.insert(nNonce); // replay guard: credit each nonce once per job
2981 int64 shareTime = GetTime(); 3019 int64 shareTime = GetTime();
2982 m->lastSeen = shareTime; 3020 m->lastSeen = shareTime;
2983 roundShareCount[m->address]++; 3021 roundShareCount[m->address]++;