Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 34 additions & 12 deletions lib/pool/shares.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,18 @@ module.exports = function createShareProcessor(deps) {
walletLastSeeTime[miner.payout] = Date.now();
}

function getVerifyRetryLimit() {
const verifyConfig = global.config.pool && global.config.pool.verifyShareRetry;
if (!verifyConfig || typeof verifyConfig.maxRetries !== "number") return 3;
return Math.max(0, Math.floor(verifyConfig.maxRetries));
}

function getVerifyRetryDelayMs() {
const verifyConfig = global.config.pool && global.config.pool.verifyShareRetry;
if (!verifyConfig || typeof verifyConfig.retryDelayMs !== "number") return 30;
return Math.max(0, Math.floor(verifyConfig.retryDelayMs));
}

function storeShareDiv(miner, shareReward, shareReward2, shareNum, workerName, btPort, btHeight, btDifficulty, isBlockCandidate, isTrustedShare) {
const timeNow = Date.now();
if (miner.payout_div === null) {
Expand Down Expand Up @@ -462,18 +474,28 @@ module.exports = function createShareProcessor(deps) {

function verifySlowShare(hashDiff, resultBuff, resultHash, blockData, convertedBlob, verifyShareCB) {
const timeNow = Date.now();
global.coinFuncs.slowHashAsync(convertedBlob, blockTemplate, miner.payout, function (hash) {
if (hash === null) return processShareCB(null);
if (hash !== resultHash) {
reportMinerShare(miner, job);
return processShareCB(invalidShare(miner));
}
miner.lastSlowHashAsyncDelay = Date.now() - timeNow;
if (miner.lastSlowHashAsyncDelay > 1000) miner.lastSlowHashAsyncDelay = 1000;
ensureWalletTrustEntry(miner);
walletTrust[miner.payout] += job.rewarded_difficulty2;
return verifyShareCB(hashDiff, resultBuff, blockData, false, false);
});
const maxRetries = getVerifyRetryLimit();
const retryDelayMs = getVerifyRetryDelayMs();
let retries = 0;
const verifyOnce = function () {
global.coinFuncs.slowHashAsync(convertedBlob, blockTemplate, miner.payout, function (hash) {
if (hash === null) return processShareCB(null);
if (hash === false && retries < maxRetries) {
retries += 1;
return setTimeout(verifyOnce, retryDelayMs);
}
if (hash !== resultHash) {
reportMinerShare(miner, job);
return processShareCB(invalidShare(miner));
}
miner.lastSlowHashAsyncDelay = Date.now() - timeNow;
if (miner.lastSlowHashAsyncDelay > 1000) miner.lastSlowHashAsyncDelay = 1000;
ensureWalletTrustEntry(miner);
walletTrust[miner.payout] += job.rewarded_difficulty2;
return verifyShareCB(hashDiff, resultBuff, blockData, false, false);
});
};
verifyOnce();
}

const verifyShare = function (verifyShareCB) {
Expand Down
45 changes: 45 additions & 0 deletions tests/pool/validation/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const {
VALID_RESULT,
startHarness,
invokePoolMethod,
flushTimers,
poolModule
} = require("../common/harness.js");

Expand Down Expand Up @@ -225,6 +226,50 @@ test("submit accepts shares when the verifier returns the hash in reverse byte o
}
});

test("submit retries async verifier when verifier result is unknown", async () => {
const { runtime, database } = await startHarness();
const socket = {};
const originalSlowHashAsync = global.coinFuncs.slowHashAsync;
const originalVerifyRetryConfig = global.config.pool.verifyShareRetry;
let slowHashCalls = 0;

try {
global.config.pool.verifyShareRetry = { maxRetries: 3, retryDelayMs: 0 };
global.coinFuncs.slowHashAsync = function unknownThenValidHash(_buffer, _blockTemplate, _wallet, callback) {
slowHashCalls += 1;
if (slowHashCalls < 4) return callback(false);
callback(VALID_RESULT);
};

const loginReply = invokePoolMethod({
socket,
id: 134,
method: "login",
params: { login: MAIN_WALLET, pass: "worker-remote-retry" }
});
const jobId = loginReply.replies[0].result.job.job_id;

const submitReply = invokePoolMethod({
socket,
id: 135,
method: "submit",
params: { id: socket.miner_id, job_id: jobId, nonce: "0000000c", result: VALID_RESULT }
});

for (let i = 0; i < 10 && submitReply.replies.length === 0; ++i) {
await flushTimers();
}
assert.deepEqual(submitReply.replies, [{ error: null, result: { status: "OK" } }]);
assert.equal(slowHashCalls, 4);
assert.equal(runtime.getState().shareStats.invalidShares, 0);
assert.equal(database.invalidShares.length, 0);
} finally {
global.config.pool.verifyShareRetry = originalVerifyRetryConfig;
global.coinFuncs.slowHashAsync = originalSlowHashAsync;
await runtime.stop();
}
});

test("wallet bans propagated through messageHandler reject later logins", async () => {
const { runtime } = await startHarness();
const cluster = require("cluster");
Expand Down
Loading