UNPKG

@node-dlc/chainmon

Version:
144 lines 5.24 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BlockWatcher = void 0; const bitcoin_1 = require("@node-dlc/bitcoin"); const bitcoinjs_lib_1 = require("bitcoinjs-lib"); const events_1 = require("events"); class BlockWatcher extends events_1.EventEmitter { /** * TxWatcher listens for transactions that match certain patterns * and events when a transaction is found matching the pattern * * @param client */ constructor(client) { super(); this._client = client; this.watchedOutPoints = new Map(); this.watchedScriptPubKeys = new Map(); this.receivedBlocks = new Map(); this.previousHashToHash = new Map(); } /** * Starts watching for transactions */ start(latestBlock) { this.receivedBlocks.set(latestBlock.hash, latestBlock); this._client.subscribeRawBlock(); this._client.on('rawblock', this._onRawBlock.bind(this)); } /** * Stops watching for transactions */ stop() { // this._client.close(); } /** * Watches an outpoint for broadcase in a new transaction * @param outpoint */ watchOutpoint(outpoint) { const key = outpoint.toString(); this.watchedOutPoints.set(key, outpoint); } /** * Watches a scriptpubkey for broadcast in a new transaction * @param scriptPubKey * @param value */ watchScriptPubKey(scriptPubKey, value) { const key = scriptPubKey.toString(); this.watchedScriptPubKeys.set(key, [scriptPubKey, value]); } //////////////////////////////////////////////////////////////// _checkOutpoints(block, tx) { for (const vin of tx.inputs) { const key = vin.outpoint.toString(); const watchedOutpoint = this.watchedOutPoints.get(key); if (watchedOutpoint) { this.watchedOutPoints.delete(key); this.emit('outpointspent', block, tx, watchedOutpoint); } } } _checkScriptPubkeys(block, tx) { for (const vout of tx.outputs) { const key = vout.scriptPubKey.toString(); const watchedScriptPubKey = this.watchedScriptPubKeys.get(key); if (watchedScriptPubKey) { const [, value] = watchedScriptPubKey; if (!value || (value && vout.value === value)) { this.watchedScriptPubKeys.delete(key); this.emit('scriptpubkeyreceived', block, tx, watchedScriptPubKey); } } } } _onRawBlock(buf) { const block = bitcoinjs_lib_1.Block.fromBuffer(buf); let txs; for (const transaction of block.transactions) { if (!txs) txs = [transaction.getId()]; } const previousblockhash = Buffer.from(block.prevHash) .reverse() .toString('hex'); const previousBlock = this.receivedBlocks.get(previousblockhash); const blockSize = buf.length; if (previousBlock) { this._processBlock(block, blockSize, txs, previousBlock); } else { this._findPreviousBlockAndProcess(buf, previousblockhash); } } _processBlock(block, blockSize, txs, previousBlock) { const blockHash = block.getId(); const blockSummary = { hash: blockHash, confirmations: 1, size: blockSize, weight: block.weight(), height: previousBlock.height + 1, version: block.version, versionHex: '', merkleroot: block.merkleRoot.toString('hex'), tx: txs, time: block.timestamp, mediantime: block.timestamp, nonce: block.nonce, bits: '', difficulty: '', chainwork: '', nTx: block.transactions.length, previousblockhash: previousBlock.hash, nextblockhash: '', }; this.receivedBlocks.set(blockSummary.hash, blockSummary); for (const transaction of block.transactions) { try { const tx = bitcoin_1.Tx.fromBuffer(transaction.toBuffer()); this._checkOutpoints(blockSummary, tx); this._checkScriptPubkeys(blockSummary, tx); } catch (e) { console.error('Failed to deserialize tx', transaction.toBuffer().toString('hex')); } } const existingBlockWithPrevHash = this.previousHashToHash.get(blockSummary.previousblockhash); if (existingBlockWithPrevHash) { this.emit('orphanblock', existingBlockWithPrevHash, blockSummary.hash); } else { this.previousHashToHash.set(blockSummary.previousblockhash, blockSummary.hash); } } async _findPreviousBlockAndProcess(currentBlockBuf, previousblockhash) { const previousBuf = await this._client.getRawBlock(previousblockhash); this._onRawBlock(previousBuf); this._onRawBlock(currentBlockBuf); } } exports.BlockWatcher = BlockWatcher; //# sourceMappingURL=BlockWatcher.js.map