proxy diff working

This commit is contained in:
Ben Wilson
2023-08-13 23:26:06 -04:00
parent 5369b2dc12
commit 42235736fa
15 changed files with 504 additions and 20 deletions
+9 -2
View File
@@ -4,8 +4,8 @@ BITCOIN_RPC_PASSWORD=
BITCOIN_RPC_PORT=8332 BITCOIN_RPC_PORT=8332
BITCOIN_RPC_TIMEOUT=10000 BITCOIN_RPC_TIMEOUT=10000
#statum port API_PORT=3334
PORT=3333 STRATUM_PORT=3333
#optional telegram bot #optional telegram bot
#TELEGRAM_BOT_TOKEN= #TELEGRAM_BOT_TOKEN=
@@ -21,3 +21,10 @@ DEV_FEE_ADDRESS=
NETWORK=mainnet NETWORK=mainnet
API_SECURE=false API_SECURE=false
ENABLE_SOLO=false
ENABLE_PROXY=true
BRAIINS_ACCESS_TOKEN=
PROXY_PORT=3333
+1
View File
@@ -1,6 +1,7 @@
{ {
"cSpell.words": [ "cSpell.words": [
"bitcoinjs", "bitcoinjs",
"braiins",
"coinb", "coinb",
"coinbasevalue", "coinbasevalue",
"Fastify", "Fastify",
+98
View File
@@ -9,6 +9,7 @@
"version": "0.0.1", "version": "0.0.1",
"license": "UNLICENSED", "license": "UNLICENSED",
"dependencies": { "dependencies": {
"@nestjs/axios": "^3.0.0",
"@nestjs/cache-manager": "^2.0.1", "@nestjs/cache-manager": "^2.0.1",
"@nestjs/common": "^9.0.0", "@nestjs/common": "^9.0.0",
"@nestjs/config": "^2.3.2", "@nestjs/config": "^2.3.2",
@@ -16,6 +17,7 @@
"@nestjs/platform-fastify": "^9.4.2", "@nestjs/platform-fastify": "^9.4.2",
"@nestjs/schedule": "^3.0.1", "@nestjs/schedule": "^3.0.1",
"@nestjs/typeorm": "^10.0.0", "@nestjs/typeorm": "^10.0.0",
"axios": "^1.4.0",
"big.js": "^6.2.1", "big.js": "^6.2.1",
"bitcoin-address-validation": "^2.2.1", "bitcoin-address-validation": "^2.2.1",
"bitcoinjs-lib": "^6.1.3", "bitcoinjs-lib": "^6.1.3",
@@ -1657,6 +1659,17 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/@nestjs/axios": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-3.0.0.tgz",
"integrity": "sha512-ULdH03jDWkS5dy9X69XbUVbhC+0pVnrRcj7bIK/ytTZ76w7CgvTZDJqsIyisg3kNOiljRW/4NIjSf3j6YGvl+g==",
"peerDependencies": {
"@nestjs/common": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0",
"axios": "^1.3.1",
"reflect-metadata": "^0.1.12",
"rxjs": "^6.0.0 || ^7.0.0"
}
},
"node_modules/@nestjs/cache-manager": { "node_modules/@nestjs/cache-manager": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@nestjs/cache-manager/-/cache-manager-2.0.1.tgz", "resolved": "https://registry.npmjs.org/@nestjs/cache-manager/-/cache-manager-2.0.1.tgz",
@@ -3229,6 +3242,29 @@
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz",
"integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==" "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg=="
}, },
"node_modules/axios": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz",
"integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==",
"dependencies": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/axios/node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/babel-jest": { "node_modules/babel-jest": {
"version": "29.5.0", "version": "29.5.0",
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz",
@@ -5388,6 +5424,25 @@
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
"dev": true "dev": true
}, },
"node_modules/follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/for-each": { "node_modules/for-each": {
"version": "0.3.3", "version": "0.3.3",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
@@ -8974,6 +9029,11 @@
"node": ">= 0.10" "node": ">= 0.10"
} }
}, },
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/psl": { "node_modules/psl": {
"version": "1.9.0", "version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
@@ -12546,6 +12606,12 @@
} }
} }
}, },
"@nestjs/axios": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-3.0.0.tgz",
"integrity": "sha512-ULdH03jDWkS5dy9X69XbUVbhC+0pVnrRcj7bIK/ytTZ76w7CgvTZDJqsIyisg3kNOiljRW/4NIjSf3j6YGvl+g==",
"requires": {}
},
"@nestjs/cache-manager": { "@nestjs/cache-manager": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@nestjs/cache-manager/-/cache-manager-2.0.1.tgz", "resolved": "https://registry.npmjs.org/@nestjs/cache-manager/-/cache-manager-2.0.1.tgz",
@@ -13764,6 +13830,28 @@
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz",
"integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==" "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg=="
}, },
"axios": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz",
"integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==",
"requires": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
},
"dependencies": {
"form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
}
}
},
"babel-jest": { "babel-jest": {
"version": "29.5.0", "version": "29.5.0",
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz",
@@ -15427,6 +15515,11 @@
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
"dev": true "dev": true
}, },
"follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
},
"for-each": { "for-each": {
"version": "0.3.3", "version": "0.3.3",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
@@ -18132,6 +18225,11 @@
"ipaddr.js": "1.9.1" "ipaddr.js": "1.9.1"
} }
}, },
"proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"psl": { "psl": {
"version": "1.9.0", "version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
+2
View File
@@ -20,6 +20,7 @@
"test:e2e": "jest --config ./test/jest-e2e.json" "test:e2e": "jest --config ./test/jest-e2e.json"
}, },
"dependencies": { "dependencies": {
"@nestjs/axios": "^3.0.0",
"@nestjs/cache-manager": "^2.0.1", "@nestjs/cache-manager": "^2.0.1",
"@nestjs/common": "^9.0.0", "@nestjs/common": "^9.0.0",
"@nestjs/config": "^2.3.2", "@nestjs/config": "^2.3.2",
@@ -27,6 +28,7 @@
"@nestjs/platform-fastify": "^9.4.2", "@nestjs/platform-fastify": "^9.4.2",
"@nestjs/schedule": "^3.0.1", "@nestjs/schedule": "^3.0.1",
"@nestjs/typeorm": "^10.0.0", "@nestjs/typeorm": "^10.0.0",
"axios": "^1.4.0",
"big.js": "^6.2.1", "big.js": "^6.2.1",
"bitcoin-address-validation": "^2.2.1", "bitcoin-address-validation": "^2.2.1",
"bitcoinjs-lib": "^6.1.3", "bitcoinjs-lib": "^6.1.3",
+9 -2
View File
@@ -1,3 +1,4 @@
import { HttpModule } from '@nestjs/axios';
import { CacheModule } from '@nestjs/cache-manager'; import { CacheModule } from '@nestjs/cache-manager';
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config'; import { ConfigModule } from '@nestjs/config';
@@ -15,8 +16,11 @@ import { ClientModule } from './ORM/client/client.module';
import { TelegramSubscriptionsModule } from './ORM/telegram-subscriptions/telegram-subscriptions.module'; import { TelegramSubscriptionsModule } from './ORM/telegram-subscriptions/telegram-subscriptions.module';
import { AppService } from './services/app.service'; import { AppService } from './services/app.service';
import { BitcoinRpcService } from './services/bitcoin-rpc.service'; import { BitcoinRpcService } from './services/bitcoin-rpc.service';
import { BraiinsService } from './services/braiins.service';
import { BTCPayService } from './services/btc-pay.service';
import { DiscordService } from './services/discord.service'; import { DiscordService } from './services/discord.service';
import { NotificationService } from './services/notification.service'; import { NotificationService } from './services/notification.service';
import { ProxyService } from './services/proxy.service';
import { StratumV1JobsService } from './services/stratum-v1-jobs.service'; import { StratumV1JobsService } from './services/stratum-v1-jobs.service';
import { StratumV1Service } from './services/stratum-v1.service'; import { StratumV1Service } from './services/stratum-v1.service';
import { TelegramService } from './services/telegram.service'; import { TelegramService } from './services/telegram.service';
@@ -44,7 +48,7 @@ const ORMModules = [
}), }),
CacheModule.register(), CacheModule.register(),
ScheduleModule.forRoot(), ScheduleModule.forRoot(),
HttpModule,
...ORMModules ...ORMModules
], ],
controllers: [ controllers: [
@@ -60,7 +64,10 @@ const ORMModules = [
BitcoinRpcService, BitcoinRpcService,
NotificationService, NotificationService,
BitcoinAddressValidator, BitcoinAddressValidator,
StratumV1JobsService StratumV1JobsService,
ProxyService,
BTCPayService,
BraiinsService
], ],
}) })
export class AppModule { export class AppModule {
+2 -2
View File
@@ -10,7 +10,7 @@ import { AppModule } from './app.module';
async function bootstrap() { async function bootstrap() {
if (process.env.PORT == null) { if (process.env.API_PORT == null) {
console.error('It appears your environment is not configured, create and populate an .env file.'); console.error('It appears your environment is not configured, create and populate an .env file.');
return; return;
} }
@@ -45,7 +45,7 @@ async function bootstrap() {
//Taproot //Taproot
bitcoinjs.initEccLib(ecc); bitcoinjs.initEccLib(ecc);
await app.listen(process.env.PORT, '0.0.0.0', (err, address) => { await app.listen(process.env.API_PORT, '0.0.0.0', (err, address) => {
console.log(`API listening on ${address}`); console.log(`API listening on ${address}`);
}); });
+2 -1
View File
@@ -3,6 +3,7 @@ import * as bitcoinjs from 'bitcoinjs-lib';
import { IJobTemplate } from '../services/stratum-v1-jobs.service'; import { IJobTemplate } from '../services/stratum-v1-jobs.service';
import { eResponseMethod } from './enums/eResponseMethod'; import { eResponseMethod } from './enums/eResponseMethod';
import { IMiningNotify } from './stratum-messages/IMiningNotify';
interface AddressObject { interface AddressObject {
@@ -161,7 +162,7 @@ export class MiningJob {
public response(jobTemplate: IJobTemplate): string { public response(jobTemplate: IJobTemplate): string {
const job = { const job: IMiningNotify = {
id: null, id: null,
method: eResponseMethod.MINING_NOTIFY, method: eResponseMethod.MINING_NOTIFY,
params: [ params: [
+235
View File
@@ -0,0 +1,235 @@
import Big from 'big.js';
import { Block } from 'bitcoinjs-lib';
import * as bitcoinjs from 'bitcoinjs-lib';
import { plainToInstance } from 'class-transformer';
import { validate, ValidatorOptions } from 'class-validator';
import { Socket } from 'net';
import { eRequestMethod } from './enums/eRequestMethod';
import { eResponseMethod } from './enums/eResponseMethod';
import { IMiningNotify } from './stratum-messages/IMiningNotify';
import { MiningSubmitMessage } from './stratum-messages/MiningSubmitMessage';
export class ProxyClient {
public braiinsSocket: Socket;
public serverDifficulty: number;
public jobs: { [jobId: string]: IMiningNotify } = {};
private extraNonce: string;
constructor(public socket: Socket) {
this.braiinsSocket = new Socket();
this.braiinsSocket.connect(3333, 'us-east.stratum.braiins.com', () => {
console.log('Connected to braiins');
});
this.braiinsSocket.on('data', (data) => {
data.toString()
.split('\n')
.filter(m => m.length > 0)
.forEach(async (m) => {
try {
await this.toClient(m);
} catch (e) {
await socket.end();
console.error(e);
}
})
});
this.braiinsSocket.on('close', () => {
console.log('Braiins closed connection');
socket.end();
});
socket.on('error', async (error: Error) => { });
socket.on('data', (data: Buffer) => {
data.toString()
.split('\n')
.filter(m => m.length > 0)
.forEach(async (m) => {
try {
await this.toServer(m);
} catch (e) {
await socket.end();
console.error(e);
}
})
});
socket.on('close', () => {
console.log('Client closed connection');
this.braiinsSocket.end();
})
}
private async toClient(message: string) {
let parsedMessage: IMiningNotify | any;
try {
parsedMessage = JSON.parse(message);
} catch (e) {
//console.log("Invalid JSON");
await this.socket.end();
return;
}
if (parsedMessage.method == null && Array.isArray(parsedMessage.result)) {
this.extraNonce = parsedMessage.result[1];
}
switch (parsedMessage.method) {
case eResponseMethod.SET_DIFFICULTY: {
this.serverDifficulty = parsedMessage.params[0];
parsedMessage.params[0] = 512;
message = JSON.stringify(parsedMessage);
break;
}
case eResponseMethod.MINING_NOTIFY: {
// clear jobs
if ((parsedMessage as IMiningNotify).params[8]) {
this.jobs = {};
}
this.jobs[parsedMessage.params[0]] = parsedMessage;
break;
}
}
console.log('Server:');
console.log(message);
this.socket.write(message + `\n`);
}
private async toServer(message: string) {
let parsedMessage = null;
try {
parsedMessage = JSON.parse(message);
} catch (e) {
//console.log("Invalid JSON");
await this.socket.end();
return;
}
switch (parsedMessage.method) {
case eRequestMethod.AUTHORIZE: {
parsedMessage.params[0] = 'battlechicken';
message = JSON.stringify(parsedMessage);
break;
}
case eRequestMethod.SUBMIT: {
parsedMessage.params[0] = 'battlechicken';
message = JSON.stringify(parsedMessage);
const miningSubmitMessage = plainToInstance(
MiningSubmitMessage,
parsedMessage,
);
const validatorOptions: ValidatorOptions = {
whitelist: true,
forbidNonWhitelisted: true,
};
const errors = await validate(miningSubmitMessage, validatorOptions);
if (errors.length === 0) {
this.checkSubmission(miningSubmitMessage);
}
else {
console.log('parsing error')
}
break;
}
}
console.log('Client:');
console.log(message);
this.braiinsSocket.write(message + '\n');
}
private checkSubmission(submission: MiningSubmitMessage) {
console.log('Submission:');
console.log(submission);
const job = this.jobs[submission.jobId];
if (job == null) {
console.log('Job not found');
return;
}
const versionMask = parseInt(submission.versionMask, 16);
const block = new Block();
block.version = parseInt(job.params[5], 16);
if (submission.versionMask !== undefined && versionMask != 0) {
block.version = (block.version ^ versionMask);
}
const prevHash = this.swapEndianWords(job.params[1]);
block.prevHash = Buffer.from(prevHash, 'hex');
const coinbase = Buffer.from(`${job.params[2]}${this.extraNonce}${submission.extraNonce2}${job.params[3]}`, 'hex');
const coinbaseHash = bitcoinjs.crypto.hash256(coinbase);
block.merkleRoot = this.calculateMerkleRootHash(coinbaseHash, job.params[4]);
block.timestamp = parseInt(submission.ntime, 16);
block.bits = parseInt(job.params[6], 16);
block.nonce = parseInt(submission.nonce, 16);
const header = block.toBuffer(true);
const diff = this.calculateDifficulty(header);
console.log(`DIFFICULTY: ${diff.submissionDifficulty}`)
}
private calculateMerkleRootHash(newRoot: Buffer, merkleBranches: string[]): Buffer {
const bothMerkles = Buffer.alloc(64);
bothMerkles.set(newRoot);
for (let i = 0; i < merkleBranches.length; i++) {
bothMerkles.set(Buffer.from(merkleBranches[i], 'hex'), 32);
newRoot = bitcoinjs.crypto.hash256(bothMerkles);
bothMerkles.set(newRoot);
}
return bothMerkles.subarray(0, 32)
}
private calculateDifficulty(header: Buffer): { submissionDifficulty: number, submissionHash: string } {
const hashResult = bitcoinjs.crypto.hash256(header);
let s64 = this.le256todouble(hashResult);
const truediffone = Big('26959535291011309493156476344723991336010898738574164086137773096960');
const difficulty = truediffone.div(s64.toString());
return { submissionDifficulty: difficulty.toNumber(), submissionHash: hashResult.toString('hex') };
}
private le256todouble(target: Buffer): bigint {
const number = target.reduceRight((acc, byte) => {
// Shift the number 8 bits to the left and OR with the current byte
return (acc << BigInt(8)) | BigInt(byte);
}, BigInt(0));
return number;
}
private swapEndianWords(str: string) {
const hexGroups = str.match(/.{1,8}/g);
// Reverse each group and concatenate them
const reversedHexString = hexGroups.reduce((pre, cur, indx, arr) => {
const reversed = cur.match(/.{2}/g).reverse();
return `${pre}${reversed.join('')}`;
}, '');
return reversedHexString;
}
}
@@ -0,0 +1,17 @@
import { eResponseMethod } from '../enums/eResponseMethod';
export interface IMiningNotify {
id: null,
method: eResponseMethod.MINING_NOTIFY,
params: [
string, // jobId 0
string, // prevHash 1
string, // coinbase part1 2
string, // coinbase part2 3
string[], // merkle_branch 4
string, // version 5
string, // bits 6
string, // timestamp 7
boolean // clear jobs 8
]
}
+2 -2
View File
@@ -28,7 +28,7 @@ export class AppService implements OnModuleInit {
@Cron(CronExpression.EVERY_HOUR) @Cron(CronExpression.EVERY_HOUR)
private async deleteOldStatistics() { private async deleteOldStatistics() {
if (process.env.NODE_APP_INSTANCE == null || process.env.NODE_APP_INSTANCE == '0') { if (process.env.ENABLE_SOLO == 'true' && (process.env.NODE_APP_INSTANCE == null || process.env.NODE_APP_INSTANCE == '0')) {
const deletedStatistics = await this.clientStatisticsService.deleteOldStatistics(); const deletedStatistics = await this.clientStatisticsService.deleteOldStatistics();
console.log(`Deleted ${deletedStatistics.affected} old statistics`); console.log(`Deleted ${deletedStatistics.affected} old statistics`);
const deletedClients = await this.clientService.deleteOldClients(); const deletedClients = await this.clientService.deleteOldClients();
@@ -38,7 +38,7 @@ export class AppService implements OnModuleInit {
@Cron(CronExpression.EVERY_5_MINUTES) @Cron(CronExpression.EVERY_5_MINUTES)
private async killDeadClients() { private async killDeadClients() {
if (process.env.NODE_APP_INSTANCE == null || process.env.NODE_APP_INSTANCE == '0') { if (process.env.ENABLE_SOLO == 'true' && (process.env.NODE_APP_INSTANCE == null || process.env.NODE_APP_INSTANCE == '0')) {
await this.clientService.killDeadClients(); await this.clientService.killDeadClients();
} }
} }
+36
View File
@@ -0,0 +1,36 @@
import { HttpService } from '@nestjs/axios';
import { Injectable, OnModuleInit } from '@nestjs/common';
import { map } from 'rxjs';
@Injectable()
export class BraiinsService implements OnModuleInit {
constructor(private readonly httpService: HttpService) {
}
onModuleInit() {
// this.getUserProfile().subscribe((res) => {
// console.log(`Braiins:`)
// console.log(res);
// })
// this.getBlockRewards(new Date(0), new Date()).subscribe(res => {
// console.log(`Braiins:`)
// console.log(res);
// })
}
public getUserProfile() {
return this.httpService.get(`https://pool.braiins.com/accounts/profile/json/BTC`, { headers: { 'SlushPool-Auth-Token': process.env.BRAIINS_ACCESS_TOKEN } }).pipe(
map(res => res.data)
)
}
public getBlockRewards(from: Date, to: Date) {
return this.httpService.get(`https://pool.braiins.com/accounts/block_rewards/json/BTC?from=${from.toISOString().split('T')[0]}&to=${to.toISOString().split('T')[0]}`, { headers: { 'SlushPool-Auth-Token': process.env.BRAIINS_ACCESS_TOKEN } }).pipe(
map(res => res.data)
);
}
}
+54
View File
@@ -0,0 +1,54 @@
import { HttpService } from '@nestjs/axios';
import { Injectable } from '@nestjs/common';
@Injectable()
export class BTCPayService {
constructor(private readonly httpService: HttpService) {
}
public createUser() {
const user = {
email: 'MyTestUser@gmail.com',
password: 'NOTVERYSECURE',
isAdministrator: false
}
this.httpService.post(`/api/v1/users`, user)
}
public createNewStore() {
const token = 'APIKEYTOKEN';
const store = {
Name: 'STORENAME'
}
this.httpService.post(`/api/v1/stores`, store, { headers: { Authorization: 'token ' + token } })
}
public createPullPayment() {
const token = 'APIKEYTOKEN';
const pullPayment = {
name: 'string',
description: 'string',
amount: '0.1',
currency: 'BTC',
period: 604800,
BOLT11Expiration: 30,
autoApproveClaims: false,
startsAt: 1592312018,
expiresAt: 1593129600,
paymentMethods: [
'BTC'
]
}
this.httpService.post(`/api/v1/stores/{storeId}/pull-payments`, pullPayment, { headers: { Authorization: 'token ' + token } })
}
}
+29
View File
@@ -0,0 +1,29 @@
import { Injectable, OnModuleInit } from '@nestjs/common';
import { Server, Socket } from 'net';
import { ProxyClient } from '../models/ProxyClient';
@Injectable()
export class ProxyService implements OnModuleInit {
constructor() {
}
async onModuleInit(): Promise<void> {
if (process.env.ENABLE_PROXY == 'true') {
console.log('Connecting to braiins');
const proxyServer = new Server(async (socket: Socket) => {
const proxyClient = new ProxyClient(socket);
});
proxyServer.listen(process.env.PROXY_PORT, () => {
console.log(`Proxy server is listening on port ${process.env.PROXY_PORT}`);
});
}
}
}
-1
View File
@@ -91,7 +91,6 @@ export class StratumV1JobsService {
tempCoinbaseTx.ins[0].witness = [Buffer.alloc(32, 0)]; tempCoinbaseTx.ins[0].witness = [Buffer.alloc(32, 0)];
transactions.unshift(tempCoinbaseTx); transactions.unshift(tempCoinbaseTx);
const transactionBuffers = transactions.map(tx => tx.getHash(false)); const transactionBuffers = transactions.map(tx => tx.getHash(false));
const merkleTree = merkle(transactionBuffers, bitcoinjs.crypto.hash256); const merkleTree = merkle(transactionBuffers, bitcoinjs.crypto.hash256);
+4 -6
View File
@@ -28,16 +28,14 @@ export class StratumV1Service implements OnModuleInit {
} }
async onModuleInit(): Promise<void> { async onModuleInit(): Promise<void> {
if (process.env.ENABLE_SOLO == 'true') {
//await this.clientStatisticsService.deleteAll(); //await this.clientStatisticsService.deleteAll();
await this.clientService.deleteAll(); await this.clientService.deleteAll();
this.startSocketServer(); this.startSocketServer();
} }
}
private startSocketServer() { private startSocketServer() {
const server = new Server(async (socket: Socket) => { const server = new Server(async (socket: Socket) => {
@@ -70,8 +68,8 @@ export class StratumV1Service implements OnModuleInit {
}); });
server.listen(3333, () => { server.listen(process.env.STRATUM_PORT, () => {
console.log(`Bitcoin Stratum server is listening on port ${3333}`); console.log(`Stratum server is listening on port ${process.env.STRATUM_PORT}`);
}); });
} }