mirror of
https://github.com/benjamin-wilson/public-pool.git
synced 2026-09-29 09:05:06 -07:00
constrain suggest difficulty
This commit is contained in:
@@ -462,24 +462,47 @@ describe('StratumV1Client', () => {
|
||||
expect(socket.write).toHaveBeenCalledWith(`{"id":null,"method":"mining.set_difficulty","params":[512]}\n`, expect.any(Function));
|
||||
});
|
||||
|
||||
it('should clamp suggested difficulty to the configured minimum', async () => {
|
||||
(configService.get as jest.Mock).mockImplementation((key: string) => {
|
||||
switch (key) {
|
||||
case 'STRATUM_MIN_DIFFICULTY':
|
||||
return '1';
|
||||
case 'DEV_FEE_ADDRESS':
|
||||
return 'tb1qumezefzdeqqwn5zfvgdrhxjzc5ylr39uhuxcz4';
|
||||
case 'NETWORK':
|
||||
return 'testnet';
|
||||
}
|
||||
return null;
|
||||
});
|
||||
it('should reject suggested difficulty below the protocol minimum', async () => {
|
||||
jest.spyOn(socket, 'write').mockImplementation((data) => true);
|
||||
|
||||
emitMessage(`{"id":4,"method":"mining.suggest_difficulty","params":[0]}`);
|
||||
await new Promise((r) => setTimeout(r, 1));
|
||||
|
||||
expect(socket.write).toHaveBeenCalledWith(`{"id":null,"method":"mining.set_difficulty","params":[1]}\n`, expect.any(Function));
|
||||
expect(socket.write).toHaveBeenCalledWith(
|
||||
expect.stringContaining('Suggest difficulty validation error'),
|
||||
expect.any(Function),
|
||||
);
|
||||
expect((client as any).sessionDifficulty).toBe(100000);
|
||||
});
|
||||
|
||||
it.each([12884901888, 1e303])(
|
||||
'should reject excessive suggested difficulty %s',
|
||||
async (suggestedDifficulty) => {
|
||||
jest.spyOn(socket, 'write').mockImplementation((data) => true);
|
||||
|
||||
emitMessage(`{"id":4,"method":"mining.suggest_difficulty","params":[${suggestedDifficulty}]}`);
|
||||
await new Promise((r) => setTimeout(r, 1));
|
||||
|
||||
expect(socket.write).toHaveBeenCalledWith(
|
||||
expect.stringContaining('Suggest difficulty validation error'),
|
||||
expect.any(Function),
|
||||
);
|
||||
expect((client as any).sessionDifficulty).toBe(100000);
|
||||
},
|
||||
);
|
||||
|
||||
it('should reject excessive password-provided starting difficulty', async () => {
|
||||
jest.spyOn(socket, 'write').mockImplementation((data) => true);
|
||||
|
||||
emitMessage(MockRecording1.MINING_SUBSCRIBE);
|
||||
emitMessage(`{"id":3,"method":"mining.authorize","params":["tb1qumezefzdeqqwn5zfvgdrhxjzc5ylr39uhuxcz4.worker","d=12884901888"]}`);
|
||||
await new Promise((r) => setTimeout(r, 1));
|
||||
|
||||
expect(socket.write).toHaveBeenCalledWith(
|
||||
expect.stringContaining('Authorization validation error'),
|
||||
expect.any(Function),
|
||||
);
|
||||
expect((client as any).sessionDifficulty).toBe(100000);
|
||||
});
|
||||
|
||||
it('should set difficulty', async () => {
|
||||
@@ -535,7 +558,7 @@ describe('StratumV1Client', () => {
|
||||
jest.spyOn(client as any, 'write').mockImplementation((data) => Promise.resolve(true));
|
||||
|
||||
emitMessage(MockRecording1.MINING_SUBSCRIBE);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [0]}`);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [1e-9]}`);
|
||||
emitMessage(MockRecording1.MINING_AUTHORIZE);
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
emitMessage(MockRecording1.MINING_SUBMIT);
|
||||
@@ -563,7 +586,7 @@ describe('StratumV1Client', () => {
|
||||
|
||||
|
||||
emitMessage(MockRecording1.MINING_SUBSCRIBE);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [0]}`);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [1e-9]}`);
|
||||
emitMessage(MockRecording1.MINING_AUTHORIZE);
|
||||
|
||||
|
||||
@@ -589,7 +612,7 @@ describe('StratumV1Client', () => {
|
||||
sessionId: MockRecording1.EXTRA_NONCE,
|
||||
jobId: '1',
|
||||
jobTemplateId: '1',
|
||||
creditedDifficulty: 0,
|
||||
creditedDifficulty: 1e-9,
|
||||
isBlockCandidate: false,
|
||||
}));
|
||||
});
|
||||
@@ -600,7 +623,7 @@ describe('StratumV1Client', () => {
|
||||
const fullBlockSpy = jest.spyOn(MiningJob.prototype, 'copyAndUpdateBlock');
|
||||
|
||||
emitMessage(MockRecording1.MINING_SUBSCRIBE);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [0]}`);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [1e-9]}`);
|
||||
emitMessage(MockRecording1.MINING_AUTHORIZE);
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
|
||||
@@ -616,7 +639,7 @@ describe('StratumV1Client', () => {
|
||||
jest.spyOn(client as any, 'write').mockImplementation((data) => Promise.resolve(true));
|
||||
|
||||
emitMessage(MockRecording1.MINING_SUBSCRIBE);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [0]}`);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [1e-9]}`);
|
||||
emitMessage(MockRecording1.MINING_AUTHORIZE);
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
|
||||
@@ -650,7 +673,7 @@ describe('StratumV1Client', () => {
|
||||
const clientUpdateIfHigherSpy = jest.spyOn(clientService as any, 'updateBestDifficultyIfHigher').mockResolvedValue({ affected: 1 });
|
||||
|
||||
emitMessage(MockRecording1.MINING_SUBSCRIBE);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [0]}`);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [1e-9]}`);
|
||||
emitMessage(MockRecording1.MINING_AUTHORIZE);
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
|
||||
@@ -724,7 +747,7 @@ describe('StratumV1Client', () => {
|
||||
jest.spyOn(client as any, 'write').mockImplementation((data) => Promise.resolve(true));
|
||||
|
||||
emitMessage(MockRecording1.MINING_SUBSCRIBE);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [0]}`);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [1e-9]}`);
|
||||
emitMessage(MockRecording1.MINING_AUTHORIZE);
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
|
||||
@@ -746,7 +769,7 @@ describe('StratumV1Client', () => {
|
||||
});
|
||||
|
||||
emitMessage(MockRecording1.MINING_SUBSCRIBE);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [0]}`);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [1e-9]}`);
|
||||
emitMessage(MockRecording1.MINING_AUTHORIZE);
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
|
||||
@@ -765,7 +788,7 @@ describe('StratumV1Client', () => {
|
||||
jest.spyOn(client as any, 'write').mockImplementation((data) => Promise.resolve(true));
|
||||
|
||||
emitMessage(MockRecording1.MINING_SUBSCRIBE);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [0]}`);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [1e-9]}`);
|
||||
emitMessage(MockRecording1.MINING_AUTHORIZE);
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
|
||||
@@ -790,7 +813,7 @@ describe('StratumV1Client', () => {
|
||||
const calculateDifficultySpy = jest.spyOn(client as any, 'calculateDifficulty');
|
||||
|
||||
emitMessage(MockRecording1.MINING_SUBSCRIBE);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [0]}`);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [1e-9]}`);
|
||||
emitMessage(MockRecording1.MINING_AUTHORIZE);
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
|
||||
@@ -828,7 +851,7 @@ describe('StratumV1Client', () => {
|
||||
});
|
||||
|
||||
emitMessage(MockRecording1.MINING_SUBSCRIBE);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [0]}`);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [1e-9]}`);
|
||||
emitMessage(MockRecording1.MINING_AUTHORIZE);
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
|
||||
@@ -853,7 +876,7 @@ describe('StratumV1Client', () => {
|
||||
jest.spyOn(socket, 'write').mockImplementation(() => true);
|
||||
|
||||
emitMessage(MockRecording1.MINING_SUBSCRIBE);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [0]}`);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [1e-9]}`);
|
||||
emitMessage(MockRecording1.MINING_AUTHORIZE);
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
|
||||
@@ -907,7 +930,7 @@ describe('StratumV1Client', () => {
|
||||
const buildHeaderSpy = jest.spyOn(MiningJob.prototype, 'buildHeaderBuffer');
|
||||
|
||||
emitMessage(MockRecording1.MINING_SUBSCRIBE);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [0]}`);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [1e-9]}`);
|
||||
emitMessage(MockRecording1.MINING_AUTHORIZE);
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
|
||||
@@ -937,7 +960,7 @@ describe('StratumV1Client', () => {
|
||||
});
|
||||
|
||||
emitMessage(MockRecording1.MINING_SUBSCRIBE);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [0]}`);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [1e-9]}`);
|
||||
emitMessage(MockRecording1.MINING_AUTHORIZE);
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
|
||||
@@ -974,7 +997,7 @@ describe('StratumV1Client', () => {
|
||||
});
|
||||
|
||||
emitMessage(MockRecording1.MINING_SUBSCRIBE);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [0]}`);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [1e-9]}`);
|
||||
emitMessage(MockRecording1.MINING_AUTHORIZE);
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
|
||||
@@ -1000,7 +1023,7 @@ describe('StratumV1Client', () => {
|
||||
const hashSpy = jest.spyOn(MiningSubmitMessage.prototype, 'hash');
|
||||
|
||||
emitMessage(MockRecording1.MINING_SUBSCRIBE);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [0]}`);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [1e-9]}`);
|
||||
emitMessage(MockRecording1.MINING_AUTHORIZE);
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
|
||||
@@ -1017,7 +1040,7 @@ describe('StratumV1Client', () => {
|
||||
jest.spyOn(client as any, 'write').mockImplementation((data) => Promise.resolve(true));
|
||||
|
||||
emitMessage(MockRecording1.MINING_SUBSCRIBE);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [0]}`);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [1e-9]}`);
|
||||
emitMessage(MockRecording1.MINING_AUTHORIZE);
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
stratumV1JobsService.blocks = {};
|
||||
@@ -1053,7 +1076,7 @@ describe('StratumV1Client', () => {
|
||||
const calculateDifficultySpy = jest.spyOn(client as any, 'calculateDifficulty');
|
||||
|
||||
emitMessage(MockRecording1.MINING_SUBSCRIBE);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [0]}`);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [1e-9]}`);
|
||||
emitMessage(MockRecording1.MINING_AUTHORIZE);
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
|
||||
@@ -1074,7 +1097,7 @@ describe('StratumV1Client', () => {
|
||||
jest.spyOn(client as any, 'write').mockImplementation(() => Promise.resolve(true));
|
||||
|
||||
emitMessage(MockRecording1.MINING_SUBSCRIBE);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [0]}`);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [1e-9]}`);
|
||||
emitMessage(MockRecording1.MINING_AUTHORIZE);
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
|
||||
@@ -1201,7 +1224,7 @@ describe('StratumV1Client', () => {
|
||||
jest.spyOn(addressSettings, 'resetBestDifficultyAndShares').mockResolvedValue(undefined);
|
||||
|
||||
emitMessage(MockRecording1.MINING_SUBSCRIBE);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [0]}`);
|
||||
emitMessage(`{"id": 4, "method": "mining.suggest_difficulty", "params": [1e-9]}`);
|
||||
emitMessage(MockRecording1.MINING_AUTHORIZE);
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
|
||||
|
||||
@@ -464,8 +464,11 @@ export class StratumV1Client {
|
||||
}
|
||||
|
||||
this.backgroundWork.push(
|
||||
setInterval(async () => {
|
||||
await this.checkDifficulty();
|
||||
setInterval(() => {
|
||||
void this.checkDifficulty().catch((error) => {
|
||||
console.error('Stratum difficulty check failed; closing client connection', error);
|
||||
this.closeSocket();
|
||||
});
|
||||
}, 60 * 1000)
|
||||
);
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Expose, Transform } from 'class-transformer';
|
||||
import { ArrayMaxSize, ArrayMinSize, IsArray, IsNumber, IsOptional, IsString, MaxLength } from 'class-validator';
|
||||
import { ArrayMaxSize, ArrayMinSize, IsArray, IsNumber, IsOptional, IsPositive, IsString, Max, MaxLength } from 'class-validator';
|
||||
|
||||
import { eRequestMethod } from '../enums/eRequestMethod';
|
||||
import { IsBitcoinAddress } from '../validators/bitcoin-address.validator';
|
||||
import { StratumBaseMessage } from './StratumBaseMessage';
|
||||
import { MAX_STRATUM_DIFFICULTY } from './SuggestDifficultyMessage';
|
||||
|
||||
export class AuthorizationMessage extends StratumBaseMessage {
|
||||
|
||||
@@ -35,6 +36,8 @@ export class AuthorizationMessage extends StratumBaseMessage {
|
||||
|
||||
@Expose()
|
||||
@IsNumber()
|
||||
@IsPositive()
|
||||
@Max(MAX_STRATUM_DIFFICULTY)
|
||||
@Transform(({ value, key, obj, type }) => {
|
||||
const password: string | null = obj.params[1];
|
||||
if (password?.includes('d=')) {
|
||||
@@ -69,4 +72,4 @@ export class AuthorizationMessage extends StratumBaseMessage {
|
||||
result: true
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { Expose, Transform } from 'class-transformer';
|
||||
import { ArrayMaxSize, ArrayMinSize, IsArray, IsNumber } from 'class-validator';
|
||||
import { ArrayMaxSize, ArrayMinSize, IsArray, IsNumber, IsPositive, Max } from 'class-validator';
|
||||
|
||||
import { eRequestMethod } from '../enums/eRequestMethod';
|
||||
import { eResponseMethod } from '../enums/eResponseMethod';
|
||||
import { StratumBaseMessage } from './StratumBaseMessage';
|
||||
|
||||
export const MAX_STRATUM_DIFFICULTY = 2 ** 32;
|
||||
|
||||
export class SuggestDifficulty extends StratumBaseMessage {
|
||||
@IsArray()
|
||||
@ArrayMinSize(1)
|
||||
@@ -16,6 +18,8 @@ export class SuggestDifficulty extends StratumBaseMessage {
|
||||
|
||||
@Expose()
|
||||
@IsNumber()
|
||||
@IsPositive()
|
||||
@Max(MAX_STRATUM_DIFFICULTY)
|
||||
@Transform(({ value, key, obj, type }) => {
|
||||
return Number(obj.params[0]);
|
||||
})
|
||||
@@ -37,4 +41,3 @@ export class SuggestDifficulty extends StratumBaseMessage {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user