3 Commits
Author SHA1 Message Date
Ben ee772e9a3c Add Blitzpool attribution headers 2026-06-22 10:40:01 -04:00
Ben 7cfcc87f94 Fix active client session index 2026-06-22 10:10:34 -04:00
Ben da85871165 Make PM2 worker memory restart opt-in 2026-06-22 10:06:00 -04:00
24 changed files with 154 additions and 4 deletions
+3 -1
View File
@@ -31,7 +31,9 @@ STRATUM_PORTS=3333,3332,3331,3330
# Optional PPLNS-mode SV1/SV2 autodetect ports. # Optional PPLNS-mode SV1/SV2 autodetect ports.
#PPLNS_STRATUM_PORTS= #PPLNS_STRATUM_PORTS=
STRATUM_WORKERS=2 STRATUM_WORKERS=2
STRATUM_WORKER_MAX_MEMORY_RESTART=4096M # Optional PM2 per-worker memory recycle. Leave unset unless you accept PM2
# restarting workers when this limit is reached.
#STRATUM_WORKER_MAX_MEMORY_RESTART=4096M
STRATUM_MIN_DIFFICULTY=1 STRATUM_MIN_DIFFICULTY=1
STRATUM_SOCKET_TIMEOUT_MS=3600000 STRATUM_SOCKET_TIMEOUT_MS=3600000
STRATUM_TCP_KEEPALIVE_INITIAL_DELAY_MS=60000 STRATUM_TCP_KEEPALIVE_INITIAL_DELAY_MS=60000
+7 -1
View File
@@ -4,6 +4,12 @@ const dockerLogConfig = {
merge_logs: true, merge_logs: true,
}; };
const stratumWorkerMemoryLimit = process.env.STRATUM_WORKER_MAX_MEMORY_RESTART;
const stratumWorkerMemoryRestart =
stratumWorkerMemoryLimit && !['0', 'false', 'off', 'disabled'].includes(stratumWorkerMemoryLimit.toLowerCase())
? { max_memory_restart: stratumWorkerMemoryLimit }
: {};
module.exports = { module.exports = {
apps: [ apps: [
// API instance // API instance
@@ -42,7 +48,7 @@ module.exports = {
script: './dist/main.js', script: './dist/main.js',
instances: parseInt(process.env.STRATUM_WORKERS || '2', 10), instances: parseInt(process.env.STRATUM_WORKERS || '2', 10),
exec_mode: "cluster", exec_mode: "cluster",
max_memory_restart: process.env.STRATUM_WORKER_MAX_MEMORY_RESTART || '4096M', ...stratumWorkerMemoryRestart,
env: { env: {
MASTER: 'false', MASTER: 'false',
API_ENABLED: 'false', API_ENABLED: 'false',
@@ -0,0 +1,40 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class FixClientSessionActiveIndex1781320000000 implements MigrationInterface {
public name = 'FixClientSessionActiveIndex1781320000000';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP INDEX IF EXISTS "IDX_unique_nonce"`);
await queryRunner.query(`
DELETE FROM "client_entity"
WHERE ctid IN (
SELECT ctid
FROM (
SELECT
ctid,
row_number() OVER (
PARTITION BY "sessionId"
ORDER BY "updatedAt" DESC, "createdAt" DESC, "id" DESC
) AS rn
FROM "client_entity"
WHERE "deletedAt" IS NULL
) duplicates
WHERE rn > 1
)
`);
await queryRunner.query(`
CREATE UNIQUE INDEX "IDX_unique_nonce"
ON "client_entity" ("sessionId")
WHERE "deletedAt" IS NULL
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP INDEX IF EXISTS "IDX_unique_nonce"`);
await queryRunner.query(`
CREATE UNIQUE INDEX "IDX_unique_nonce"
ON "client_entity" ("sessionId")
WHERE "deletedAt" IS NULL
`);
}
}
@@ -1,3 +1,8 @@
/*
* Portions of this file are derived from or heavily informed by Blitzpool by warioishere.
* https://github.com/warioishere/blitzpool
*/
import { AddressType, getAddressInfo } from 'bitcoin-address-validation'; import { AddressType, getAddressInfo } from 'bitcoin-address-validation';
export interface PayoutAddressWork { export interface PayoutAddressWork {
@@ -1,3 +1,8 @@
/*
* Portions of this file are derived from or heavily informed by Blitzpool by warioishere.
* https://github.com/warioishere/blitzpool
*/
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { DataSource, EntityManager } from 'typeorm'; import { DataSource, EntityManager } from 'typeorm';
+2
View File
@@ -18,6 +18,7 @@ import { PayoutModes1781300000000 } from './ORM/_migrations/PayoutModes178130000
import { ShareRollupStoragePolicy1781305000000 } from './ORM/_migrations/ShareRollupStoragePolicy1781305000000'; import { ShareRollupStoragePolicy1781305000000 } from './ORM/_migrations/ShareRollupStoragePolicy1781305000000';
import { AcceptedShareHighScores1781309000000 } from './ORM/_migrations/AcceptedShareHighScores1781309000000'; import { AcceptedShareHighScores1781309000000 } from './ORM/_migrations/AcceptedShareHighScores1781309000000';
import { UserAgentReportNonzeroHashrate1781313000000 } from './ORM/_migrations/UserAgentReportNonzeroHashrate1781313000000'; import { UserAgentReportNonzeroHashrate1781313000000 } from './ORM/_migrations/UserAgentReportNonzeroHashrate1781313000000';
import { FixClientSessionActiveIndex1781320000000 } from './ORM/_migrations/FixClientSessionActiveIndex1781320000000';
import { UserAgentReportView } from './ORM/_views/user-agent-report/user-agent-report.view'; import { UserAgentReportView } from './ORM/_views/user-agent-report/user-agent-report.view';
import { AcceptedShareEntity } from './ORM/accepted-share/accepted-share.entity'; import { AcceptedShareEntity } from './ORM/accepted-share/accepted-share.entity';
import { AddressSettingsEntity } from './ORM/address-settings/address-settings.entity'; import { AddressSettingsEntity } from './ORM/address-settings/address-settings.entity';
@@ -62,6 +63,7 @@ export const databaseMigrations = [
ShareRollupStoragePolicy1781305000000, ShareRollupStoragePolicy1781305000000,
AcceptedShareHighScores1781309000000, AcceptedShareHighScores1781309000000,
UserAgentReportNonzeroHashrate1781313000000, UserAgentReportNonzeroHashrate1781313000000,
FixClientSessionActiveIndex1781320000000,
]; ];
export function createDatabaseOptions(env: NodeJS.ProcessEnv): TypeOrmModuleOptions & DataSourceOptions { export function createDatabaseOptions(env: NodeJS.ProcessEnv): TypeOrmModuleOptions & DataSourceOptions {
+5
View File
@@ -1,3 +1,8 @@
/*
* Portions of this file are derived from or heavily informed by Blitzpool by warioishere.
* https://github.com/warioishere/blitzpool
*/
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { getAddressInfo } from 'bitcoin-address-validation'; import { getAddressInfo } from 'bitcoin-address-validation';
import * as bitcoinjs from 'bitcoinjs-lib'; import * as bitcoinjs from 'bitcoinjs-lib';
+5
View File
@@ -1,3 +1,8 @@
/*
* Portions of this file are derived from or heavily informed by Blitzpool by warioishere.
* https://github.com/warioishere/blitzpool
*/
import * as bs58 from 'bs58'; import * as bs58 from 'bs58';
import * as crypto from 'crypto'; import * as crypto from 'crypto';
+5
View File
@@ -1,3 +1,8 @@
/*
* Portions of this file are derived from or heavily informed by Blitzpool by warioishere.
* https://github.com/warioishere/blitzpool
*/
// ── SV2 Binary Codec ──────────────────────────────────────────────── // ── SV2 Binary Codec ────────────────────────────────────────────────
// Sequential Buffer reader / accumulator-pattern writer for all SV2 // Sequential Buffer reader / accumulator-pattern writer for all SV2
// data types. All multi-byte integers are little-endian per spec. // data types. All multi-byte integers are little-endian per spec.
+5
View File
@@ -1,3 +1,8 @@
/*
* Portions of this file are derived from or heavily informed by Blitzpool by warioishere.
* https://github.com/warioishere/blitzpool
*/
// ── SV2 Protocol Constants ────────────────────────────────────────── // ── SV2 Protocol Constants ──────────────────────────────────────────
/** Standard (unencrypted) frame header: 2-byte ext+type + 3-byte length + 1-byte channel bit = 6 */ /** Standard (unencrypted) frame header: 2-byte ext+type + 3-byte length + 1-byte channel bit = 6 */
+5
View File
@@ -1,3 +1,8 @@
/*
* Portions of this file are derived from or heavily informed by Blitzpool by warioishere.
* https://github.com/warioishere/blitzpool
*/
// ── SV2 Extended Mining Channel Messages ──────────────────────────── // ── SV2 Extended Mining Channel Messages ────────────────────────────
// Interfaces + serialize/deserialize for extended channel message types. // Interfaces + serialize/deserialize for extended channel message types.
+5
View File
@@ -1,3 +1,8 @@
/*
* Portions of this file are derived from or heavily informed by Blitzpool by warioishere.
* https://github.com/warioishere/blitzpool
*/
import { SV2_EXTENDED_TOTAL_EXTRANONCE_SIZE_BYTES } from '../stratum.constants'; import { SV2_EXTENDED_TOTAL_EXTRANONCE_SIZE_BYTES } from '../stratum.constants';
// -- SV2 Extranonce Manager ------------------------------------------ // -- SV2 Extranonce Manager ------------------------------------------
+5
View File
@@ -1,3 +1,8 @@
/*
* Portions of this file are derived from or heavily informed by Blitzpool by warioishere.
* https://github.com/warioishere/blitzpool
*/
// ── SV2 Frame Encoding / Decoding ─────────────────────────────────── // ── SV2 Frame Encoding / Decoding ───────────────────────────────────
// Handles 6-byte frame headers, encrypted framing with ChaCha20-Poly1305 // Handles 6-byte frame headers, encrypted framing with ChaCha20-Poly1305
// AEAD chunking, and incremental TCP reassembly. // AEAD chunking, and incremental TCP reassembly.
+5
View File
@@ -1,3 +1,8 @@
/*
* Portions of this file are derived from or heavily informed by Blitzpool by warioishere.
* https://github.com/warioishere/blitzpool
*/
// ── SV2 Job Declaration Protocol (JDP) Messages ──────────────────── // ── SV2 Job Declaration Protocol (JDP) Messages ────────────────────
// Interfaces + serialize/deserialize for all JDP message types and // Interfaces + serialize/deserialize for all JDP message types and
// the Mining Protocol custom job bridge messages. // the Mining Protocol custom job bridge messages.
+5
View File
@@ -1,3 +1,8 @@
/*
* Portions of this file are derived from or heavily informed by Blitzpool by warioishere.
* https://github.com/warioishere/blitzpool
*/
// ── SV2 Mining Protocol Messages ──────────────────────────────────── // ── SV2 Mining Protocol Messages ────────────────────────────────────
// Interfaces + serialize/deserialize for each message needed for // Interfaces + serialize/deserialize for each message needed for
// standard mining channels. // standard mining channels.
+5
View File
@@ -1,3 +1,8 @@
/*
* Portions of this file are derived from or heavily informed by Blitzpool by warioishere.
* https://github.com/warioishere/blitzpool
*/
// ── SV2 Noise NX Handshake & Encrypted Transport ──────────────────── // ── SV2 Noise NX Handshake & Encrypted Transport ────────────────────
// Implements Noise_NX_Secp256k1+EllSwift_ChaChaPoly_SHA256 for SV2. // Implements Noise_NX_Secp256k1+EllSwift_ChaChaPoly_SHA256 for SV2.
// Server (responder) side: receives Act 1, sends Act 2, then // Server (responder) side: receives Act 1, sends Act 2, then
+5
View File
@@ -1,3 +1,8 @@
/*
* Portions of this file are derived from or heavily informed by Blitzpool by warioishere.
* https://github.com/warioishere/blitzpool
*/
// ── SipHash-2-4 ──────────────────────────────────────────────────── // ── SipHash-2-4 ────────────────────────────────────────────────────
// Pure TypeScript implementation of SipHash-2-4 for SV2 JDP short // Pure TypeScript implementation of SipHash-2-4 for SV2 JDP short
// transaction IDs. Produces 8-byte (64-bit) hashes, truncated to // transaction IDs. Produces 8-byte (64-bit) hashes, truncated to
+5
View File
@@ -1,3 +1,8 @@
/*
* Portions of this file are derived from or heavily informed by Blitzpool by warioishere.
* https://github.com/warioishere/blitzpool
*/
// ── SV2 Template Distribution Protocol (TDP) Messages ────────────── // ── SV2 Template Distribution Protocol (TDP) Messages ──────────────
// Interfaces + serialize/deserialize for all TDP message types. // Interfaces + serialize/deserialize for all TDP message types.
+5
View File
@@ -1,3 +1,8 @@
/*
* Portions of this file are derived from or heavily informed by Blitzpool by warioishere.
* https://github.com/warioishere/blitzpool
*/
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { BufferReader } from '../models/sv2/sv2-binary-codec'; import { BufferReader } from '../models/sv2/sv2-binary-codec';
import { Sv2SetCustomMiningJob } from '../models/sv2/sv2-jdp-messages'; import { Sv2SetCustomMiningJob } from '../models/sv2/sv2-jdp-messages';
+7 -2
View File
@@ -146,12 +146,17 @@ export class StratumV1Service implements OnModuleInit {
const currentClient = client; const currentClient = client;
client = null; client = null;
let initializedClient = false;
try { try {
if (currentClient != null) { if (currentClient != null) {
const initializedClient = protocol === 'v2' initializedClient = protocol === 'v2'
|| (currentClient as StratumV1Client).extraNonceAndSessionId != null; || (currentClient as StratumV1Client).extraNonceAndSessionId != null;
await currentClient.destroy(); try {
await currentClient.destroy();
} catch (error) {
console.error(`Failed to clean up Stratum client after ${reason}: ${error.message}`);
}
if (initializedClient) { if (initializedClient) {
if (reason == 'Error') { if (reason == 'Error') {
this.errorClosure++; this.errorClosure++;
@@ -1,3 +1,8 @@
/*
* Portions of this file are derived from or heavily informed by Blitzpool by warioishere.
* https://github.com/warioishere/blitzpool
*/
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import * as crypto from 'crypto'; import * as crypto from 'crypto';
@@ -1,3 +1,8 @@
/*
* Portions of this file are derived from or heavily informed by Blitzpool by warioishere.
* https://github.com/warioishere/blitzpool
*/
import { Injectable, OnModuleInit } from '@nestjs/common'; import { Injectable, OnModuleInit } from '@nestjs/common';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import * as bitcoinjs from 'bitcoinjs-lib'; import * as bitcoinjs from 'bitcoinjs-lib';
@@ -1,3 +1,8 @@
/*
* Portions of this file are derived from or heavily informed by Blitzpool by warioishere.
* https://github.com/warioishere/blitzpool
*/
import { Injectable, OnModuleInit } from '@nestjs/common'; import { Injectable, OnModuleInit } from '@nestjs/common';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import * as bitcoinjs from 'bitcoinjs-lib'; import * as bitcoinjs from 'bitcoinjs-lib';
@@ -1,3 +1,8 @@
/*
* Portions of this file are derived from or heavily informed by Blitzpool by warioishere.
* https://github.com/warioishere/blitzpool
*/
import { Injectable, OnModuleInit } from '@nestjs/common'; import { Injectable, OnModuleInit } from '@nestjs/common';
import * as bitcoinjs from 'bitcoinjs-lib'; import * as bitcoinjs from 'bitcoinjs-lib';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';