Skip to content

Commit 37c5e30

Browse files
committed
Gate proxy nonce budget on share activity
1 parent a61883c commit 37c5e30

4 files changed

Lines changed: 93 additions & 10 deletions

File tree

lib/pool/miner_registry.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ module.exports = function createMinerRegistry(deps) {
9898
miner.proxyMinerName = proxyMinerName;
9999

100100
if (!(proxyMinerName in state.proxyMiners)) {
101-
state.proxyMiners[proxyMinerName] = { connectTime: Date.now(), count: 1, hashes: 0 };
101+
state.proxyMiners[proxyMinerName] = { connectTime: Date.now(), count: 1, hashes: 0, submissionBudget: false };
102102
console.log(state.threadName + formatPoolEvent("Proxy track", { payout: proxyMinerName }));
103103
} else if (++state.proxyMiners[proxyMinerName].count > global.config.pool.workerMax) {
104104
console.error(state.threadName + formatPoolEvent("Wallet long ban", {

lib/pool/protocol.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ module.exports = function createProtocolHandler(deps) {
8484
function hasProxySubmissionBudget(miner) {
8585
if (!miner) return false;
8686
const proxyMinerName = miner.proxyMinerName || miner.payout;
87-
return !!(proxyMinerName && proxyMinerName in state.proxyMiners);
87+
const proxyMiner = proxyMinerName && state.proxyMiners[proxyMinerName];
88+
return !!(proxyMiner && proxyMiner.submissionBudget === true);
8889
}
8990

9091
function getTrackedSubmissionLimit(miner) {

lib/pool/shares.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,10 @@ module.exports = function createShareProcessor(deps) {
205205
function recordShareData(miner, job, isTrustedShare, blockTemplate) {
206206
miner.hashes += job.norm_diff;
207207
const proxyMinerName = miner.payout;
208-
if (proxyMinerName in proxyMiners) proxyMiners[proxyMinerName].hashes += job.norm_diff;
208+
if (proxyMinerName in proxyMiners) {
209+
proxyMiners[proxyMinerName].hashes += job.norm_diff;
210+
proxyMiners[proxyMinerName].submissionBudget = true;
211+
}
209212
if (miner.payout in walletTrust) walletLastSeeTime[miner.payout] = Date.now();
210213

211214
const timeNow = Date.now();
@@ -337,6 +340,7 @@ module.exports = function createShareProcessor(deps) {
337340
if (addProxyMiner(miner)) {
338341
const proxyMinerName = miner.payout;
339342
proxyMiners[proxyMinerName].hashes += job.norm_diff;
343+
proxyMiners[proxyMinerName].submissionBudget = true;
340344
adjustMinerDiff(miner);
341345
}
342346
nextProcessShareCB(null);

tests/pool/runtime/submissions.js

Lines changed: 85 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,66 @@ test("jobs reject new nonces after reaching the tracked submission cap without e
420420
}
421421
});
422422

423-
test("proxy-tracked jobs use the larger tracked submission cap", async () => {
423+
test("proxy-labeled jobs use the normal tracked submission cap before share activity", async () => {
424+
const { runtime } = await startHarness();
425+
const originalThrottlePerSec = global.config.pool.minerThrottleSharePerSec;
426+
const originalThrottleWindow = global.config.pool.minerThrottleShareWindow;
427+
const socket = {};
428+
429+
try {
430+
global.config.pool.minerThrottleSharePerSec = 2;
431+
global.config.pool.minerThrottleShareWindow = 5;
432+
433+
const loginReply = invokePoolMethod({
434+
socket,
435+
id: 201,
436+
method: "login",
437+
params: {
438+
login: MAIN_WALLET,
439+
pass: "proxy-submission-cap",
440+
agent: "attacker-controlled string containing proxy"
441+
}
442+
});
443+
const miner = runtime.getState().activeMiners.get(socket.miner_id);
444+
const jobId = loginReply.replies[0].result.job.job_id;
445+
const job = miner.validJobs.toarray().find((entry) => entry.id === jobId);
446+
const trackedSubmissionLimit = global.config.pool.minerThrottleShareWindow * global.config.pool.minerThrottleSharePerSec * 100;
447+
448+
assert.equal(miner.proxyMinerName, MAIN_WALLET);
449+
assert.equal(MAIN_WALLET in runtime.getState().proxyMiners, true);
450+
assert.equal(runtime.getState().proxyMiners[MAIN_WALLET].submissionBudget, false);
451+
452+
job.submissions = new Map();
453+
for (let index = 0; index < trackedSubmissionLimit; ++index) {
454+
job.submissions.set(index.toString(16).padStart(8, "0"), 1);
455+
}
456+
457+
const submitReply = invokePoolMethod({
458+
socket,
459+
id: 202,
460+
method: "submit",
461+
params: {
462+
id: socket.miner_id,
463+
job_id: jobId,
464+
nonce: "fffffff0",
465+
result: VALID_RESULT
466+
}
467+
});
468+
469+
assert.deepEqual(submitReply.replies, [{
470+
error: "Too many share submissions for the current job. Wait for a new job.",
471+
result: undefined
472+
}]);
473+
assert.equal(job.submissions.size, trackedSubmissionLimit);
474+
assert.equal(job.submissions.has("fffffff0"), false);
475+
} finally {
476+
global.config.pool.minerThrottleSharePerSec = originalThrottlePerSec;
477+
global.config.pool.minerThrottleShareWindow = originalThrottleWindow;
478+
await runtime.stop();
479+
}
480+
});
481+
482+
test("proxy jobs with observed share activity use the larger tracked submission cap", async () => {
424483
const { runtime } = await startHarness();
425484
const originalThrottlePerSec = global.config.pool.minerThrottleSharePerSec;
426485
const originalThrottleWindow = global.config.pool.minerThrottleShareWindow;
@@ -447,6 +506,25 @@ test("proxy-tracked jobs use the larger tracked submission cap", async () => {
447506

448507
assert.equal(miner.proxyMinerName, MAIN_WALLET);
449508
assert.equal(MAIN_WALLET in runtime.getState().proxyMiners, true);
509+
assert.equal(runtime.getState().proxyMiners[MAIN_WALLET].submissionBudget, false);
510+
511+
const firstShareReply = invokePoolMethod({
512+
socket,
513+
id: 202,
514+
method: "submit",
515+
params: {
516+
id: socket.miner_id,
517+
job_id: jobId,
518+
nonce: "fffffff0",
519+
result: VALID_RESULT
520+
}
521+
});
522+
523+
assert.deepEqual(firstShareReply.replies, [{
524+
error: null,
525+
result: { status: "OK" }
526+
}]);
527+
assert.equal(runtime.getState().proxyMiners[MAIN_WALLET].submissionBudget, true);
450528

451529
job.submissions = new Map();
452530
for (let index = 0; index < trackedSubmissionLimit - 1; ++index) {
@@ -455,12 +533,12 @@ test("proxy-tracked jobs use the larger tracked submission cap", async () => {
455533

456534
const submitReply = invokePoolMethod({
457535
socket,
458-
id: 202,
536+
id: 203,
459537
method: "submit",
460538
params: {
461539
id: socket.miner_id,
462540
job_id: jobId,
463-
nonce: "fffffff0",
541+
nonce: "fffffff1",
464542
result: VALID_RESULT
465543
}
466544
});
@@ -470,16 +548,16 @@ test("proxy-tracked jobs use the larger tracked submission cap", async () => {
470548
result: { status: "OK" }
471549
}]);
472550
assert.equal(job.submissions.size, trackedSubmissionLimit);
473-
assert.equal(job.submissions.has("fffffff0"), true);
551+
assert.equal(job.submissions.has("fffffff1"), true);
474552

475553
const cappedReply = invokePoolMethod({
476554
socket,
477-
id: 203,
555+
id: 204,
478556
method: "submit",
479557
params: {
480558
id: socket.miner_id,
481559
job_id: jobId,
482-
nonce: "fffffff1",
560+
nonce: "fffffff2",
483561
result: VALID_RESULT
484562
}
485563
});
@@ -488,7 +566,7 @@ test("proxy-tracked jobs use the larger tracked submission cap", async () => {
488566
error: "Too many share submissions for the current job. Wait for a new job.",
489567
result: undefined
490568
}]);
491-
assert.equal(job.submissions.has("fffffff1"), false);
569+
assert.equal(job.submissions.has("fffffff2"), false);
492570
} finally {
493571
global.config.pool.minerThrottleSharePerSec = originalThrottlePerSec;
494572
global.config.pool.minerThrottleShareWindow = originalThrottleWindow;

0 commit comments

Comments
 (0)