mirror of
https://github.com/benjamin-wilson/public-pool.git
synced 2026-09-29 09:05:06 -07:00
proxy diff working
This commit is contained in:
+10
-3
@@ -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=
|
||||||
@@ -20,4 +20,11 @@ DEV_FEE_ADDRESS=
|
|||||||
# mainnet | testnet
|
# mainnet | testnet
|
||||||
NETWORK=mainnet
|
NETWORK=mainnet
|
||||||
|
|
||||||
API_SECURE=false
|
API_SECURE=false
|
||||||
|
|
||||||
|
ENABLE_SOLO=false
|
||||||
|
ENABLE_PROXY=true
|
||||||
|
|
||||||
|
BRAIINS_ACCESS_TOKEN=
|
||||||
|
|
||||||
|
PROXY_PORT=3333
|
||||||
Vendored
+1
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"bitcoinjs",
|
"bitcoinjs",
|
||||||
|
"braiins",
|
||||||
"coinb",
|
"coinb",
|
||||||
"coinbasevalue",
|
"coinbasevalue",
|
||||||
"Fastify",
|
"Fastify",
|
||||||
|
|||||||
Generated
+98
@@ -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",
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -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: [
|
||||||
|
|||||||
@@ -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
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 } })
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -28,15 +28,13 @@ export class StratumV1Service implements OnModuleInit {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async onModuleInit(): Promise<void> {
|
async onModuleInit(): Promise<void> {
|
||||||
|
|
||||||
//await this.clientStatisticsService.deleteAll();
|
if (process.env.ENABLE_SOLO == 'true') {
|
||||||
|
//await this.clientStatisticsService.deleteAll();
|
||||||
await this.clientService.deleteAll();
|
await this.clientService.deleteAll();
|
||||||
|
this.startSocketServer();
|
||||||
|
}
|
||||||
this.startSocketServer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private startSocketServer() {
|
private startSocketServer() {
|
||||||
@@ -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}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user