From c7e23389aaf1dc39cc5a9923a6fe6a9d6ceff194 Mon Sep 17 00:00:00 2001 From: Dustin Butler Date: Sun, 15 Oct 2023 15:47:38 -0600 Subject: [PATCH] Use zeromq if configured --- .env.example | 4 +++ package-lock.json | 40 ++++++++++++++++++++++++++++- package.json | 3 ++- src/services/bitcoin-rpc.service.ts | 30 +++++++++++++++------- 4 files changed, 66 insertions(+), 11 deletions(-) diff --git a/.env.example b/.env.example index b3ceea5..49527ca 100644 --- a/.env.example +++ b/.env.example @@ -4,6 +4,10 @@ BITCOIN_RPC_PASSWORD= BITCOIN_RPC_PORT=8332 BITCOIN_RPC_TIMEOUT=10000 +# Enable in bitcoin.conf with +# zmqpubrawblock=tcp://*:3000 +# BITCOIN_ZMQ_HOST="tcp://192.168.1.100:3000" + API_PORT=3334 STRATUM_PORT=3333 diff --git a/package-lock.json b/package-lock.json index 8e02ad5..663e762 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,7 +34,8 @@ "rxjs": "^7.2.0", "sqlite3": "^5.1.6", "tiny-secp256k1": "^2.2.3", - "typeorm": "^0.3.17" + "typeorm": "^0.3.17", + "zeromq": "^5.3.1" }, "devDependencies": { "@nestjs/cli": "^9.0.0", @@ -8187,6 +8188,16 @@ "node": ">= 10.12.0" } }, + "node_modules/node-gyp-build": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.1.tgz", + "integrity": "sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/node-gyp/node_modules/are-we-there-yet": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", @@ -11355,6 +11366,19 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zeromq": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/zeromq/-/zeromq-5.3.1.tgz", + "integrity": "sha512-4WDF9bNWWXe8OAI319bVw5dmG4BklEk8wzFGwRQxEzKb+0mgDU5J/jtyZPo0BEusVIU1+3mRQIEdT5LtQn+aAw==", + "hasInstallScript": true, + "dependencies": { + "nan": "2.17.0", + "node-gyp-build": "^4.5.0" + }, + "engines": { + "node": ">=6.0" + } } }, "dependencies": { @@ -17662,6 +17686,11 @@ } } }, + "node-gyp-build": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.1.tgz", + "integrity": "sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==" + }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -19818,6 +19847,15 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true + }, + "zeromq": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/zeromq/-/zeromq-5.3.1.tgz", + "integrity": "sha512-4WDF9bNWWXe8OAI319bVw5dmG4BklEk8wzFGwRQxEzKb+0mgDU5J/jtyZPo0BEusVIU1+3mRQIEdT5LtQn+aAw==", + "requires": { + "nan": "2.17.0", + "node-gyp-build": "^4.5.0" + } } } } diff --git a/package.json b/package.json index a29b0d6..61adb2b 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,8 @@ "rxjs": "^7.2.0", "sqlite3": "^5.1.6", "tiny-secp256k1": "^2.2.3", - "typeorm": "^0.3.17" + "typeorm": "^0.3.17", + "zeromq": "^5.3.1" }, "devDependencies": { "@nestjs/cli": "^9.0.0", diff --git a/src/services/bitcoin-rpc.service.ts b/src/services/bitcoin-rpc.service.ts index 11c3236..69ec03d 100644 --- a/src/services/bitcoin-rpc.service.ts +++ b/src/services/bitcoin-rpc.service.ts @@ -5,6 +5,7 @@ import { BehaviorSubject, filter, shareReplay } from 'rxjs'; import { IBlockTemplate } from '../models/bitcoin-rpc/IBlockTemplate'; import { IMiningInfo } from '../models/bitcoin-rpc/IMiningInfo'; +import * as zmq from 'zeromq'; @Injectable() export class BitcoinRpcService { @@ -25,17 +26,28 @@ export class BitcoinRpcService { console.log('Bitcoin RPC connected'); - // Maybe use ZeroMQ ? - setInterval(async () => { - const miningInfo = await this.getMiningInfo(); - if (miningInfo != null && miningInfo.blocks > this.blockHeight) { - this._newBlock$.next(miningInfo); - this.blockHeight = miningInfo.blocks; - } - - }, 500); + if (this.configService.get('BITCOIN_ZMQ_HOST')) { + const sock = zmq.socket("sub"); + sock.connect(this.configService.get('BITCOIN_ZMQ_HOST')); + sock.subscribe("rawblock"); + sock.on("message", async (topic: Buffer, message: Buffer) => { + console.log("new block zmq"); + this.pollMiningInfo(); + }); + this.pollMiningInfo(); + } else { + setInterval(this.pollMiningInfo.bind(this), 500); + } } + public async pollMiningInfo() { + const miningInfo = await this.getMiningInfo(); + if (miningInfo != null && miningInfo.blocks > this.blockHeight) { + console.log("block height change"); + this._newBlock$.next(miningInfo); + this.blockHeight = miningInfo.blocks; + } + } public async getBlockTemplate(): Promise { let result: IBlockTemplate;