Add track-txs websocket subscription
This commit is contained in:
		
							parent
							
								
									8f19a376fa
								
							
						
					
					
						commit
						c5300c950b
					
				| @ -2,7 +2,7 @@ import logger from '../logger'; | ||||
| import * as WebSocket from 'ws'; | ||||
| import { | ||||
|   BlockExtended, TransactionExtended, MempoolTransactionExtended, WebsocketResponse, | ||||
|   OptimizedStatistic, ILoadingIndicators, GbtCandidates, | ||||
|   OptimizedStatistic, ILoadingIndicators, GbtCandidates, TxTrackingInfo, | ||||
| } from '../mempool.interfaces'; | ||||
| import blocks from './blocks'; | ||||
| import memPool from './mempool'; | ||||
| @ -209,6 +209,52 @@ class WebsocketHandler { | ||||
|             } | ||||
|           } | ||||
| 
 | ||||
|           if (parsedMessage && parsedMessage['track-txs']) { | ||||
|             const txids: string[] = []; | ||||
|             if (Array.isArray(parsedMessage['track-txs'])) { | ||||
|               for (const txid of parsedMessage['track-txs']) { | ||||
|                 if (/^[a-fA-F0-9]{64}$/.test(txid)) { | ||||
|                   txids.push(txid); | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
| 
 | ||||
|             const txs: { [txid: string]: TxTrackingInfo } = {}; | ||||
|             for (const txid of txids) { | ||||
|               const txInfo: TxTrackingInfo = { | ||||
|                 confirmed: true, | ||||
|               }; | ||||
|               const rbfCacheTxid = rbfCache.getReplacedBy(txid); | ||||
|               if (rbfCacheTxid) { | ||||
|                 txInfo.replacedBy = rbfCacheTxid; | ||||
|                 txInfo.confirmed = false; | ||||
|               } | ||||
|               const tx = memPool.getMempool()[txid]; | ||||
|               if (tx && tx.position) { | ||||
|                 txInfo.position = { | ||||
|                   ...tx.position | ||||
|                 }; | ||||
|                 if (tx.acceleration) { | ||||
|                   txInfo.accelerated = tx.acceleration; | ||||
|                 } | ||||
|               } | ||||
|               if (tx) { | ||||
|                 txInfo.confirmed = false; | ||||
|               } | ||||
|               txs[txid] = txInfo; | ||||
|             } | ||||
| 
 | ||||
|             if (txids.length) { | ||||
|               client['track-txs'] = txids; | ||||
|             } else { | ||||
|               client['track-txs'] = null; | ||||
|             } | ||||
| 
 | ||||
|             if (Object.keys(txs).length) { | ||||
|               response['tracked-txs'] = JSON.stringify(txs); | ||||
|             } | ||||
|           } | ||||
| 
 | ||||
|           if (parsedMessage && parsedMessage['track-address']) { | ||||
|             const validAddress = this.testAddress(parsedMessage['track-address']); | ||||
|             if (validAddress) { | ||||
| @ -517,6 +563,11 @@ class WebsocketHandler { | ||||
|       if (client['track-tx']) { | ||||
|         trackedTxs.add(client['track-tx']); | ||||
|       } | ||||
|       if (client['track-txs']) { | ||||
|         for (const txid of client['track-txs']) { | ||||
|           trackedTxs.add(client['track-tx']); | ||||
|         } | ||||
|       } | ||||
|     }); | ||||
|     if (trackedTxs.size > 0) { | ||||
|       for (const tx of newTransactions) { | ||||
| @ -713,6 +764,46 @@ class WebsocketHandler { | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       if (client['track-txs']) { | ||||
|         const txids = client['track-txs']; | ||||
|         const txs: { [txid: string]: TxTrackingInfo } = {}; | ||||
|         for (const txid of txids) { | ||||
|           const txInfo: TxTrackingInfo = {}; | ||||
|           const outspends = outspendCache[txid]; | ||||
|           if (outspends && Object.keys(outspends).length) { | ||||
|             txInfo.utxoSpent = outspends; | ||||
|           } | ||||
|           const replacedBy = rbfChanges.map[txid] ? rbfCache.getReplacedBy(txid) : false; | ||||
|           if (replacedBy) { | ||||
|             txInfo.replacedBy = replacedBy; | ||||
|           } | ||||
|           const mempoolTx = newMempool[txid]; | ||||
|           if (mempoolTx && mempoolTx.position) { | ||||
|             txInfo.position = { | ||||
|               ...mempoolTx.position, | ||||
|               accelerated: mempoolTx.acceleration || undefined, | ||||
|             }; | ||||
|             if (!mempoolTx.cpfpChecked) { | ||||
|               calculateCpfp(mempoolTx, newMempool); | ||||
|             } | ||||
|             if (mempoolTx.cpfpDirty) { | ||||
|               txInfo.cpfp = { | ||||
|                 ancestors: mempoolTx.ancestors, | ||||
|                 bestDescendant: mempoolTx.bestDescendant || null, | ||||
|                 descendants: mempoolTx.descendants || null, | ||||
|                 effectiveFeePerVsize: mempoolTx.effectiveFeePerVsize || null, | ||||
|                 sigops: mempoolTx.sigops, | ||||
|                 adjustedVsize: mempoolTx.adjustedVsize, | ||||
|               }; | ||||
|             } | ||||
|           } | ||||
|           txs[txid] = txInfo; | ||||
|         } | ||||
|         if (Object.keys(txs).length) { | ||||
|           response['tracked-txs'] = JSON.stringify(txs); | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       if (client['track-mempool-block'] >= 0 && memPool.isInSync()) { | ||||
|         const index = client['track-mempool-block']; | ||||
|         if (mBlockDeltas[index]) { | ||||
| @ -931,6 +1022,28 @@ class WebsocketHandler { | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       if (client['track-txs']) { | ||||
|         const txs: { [txid: string]: TxTrackingInfo } = {}; | ||||
|         for (const txid of client['track-txs']) { | ||||
|           if (confirmedTxids[txid]) { | ||||
|             txs[txid] = { confirmed: true }; | ||||
|           } else { | ||||
|             const mempoolTx = _memPool[txid]; | ||||
|             if (mempoolTx && mempoolTx.position) { | ||||
|               txs[txid] = { | ||||
|                 position: { | ||||
|                   ...mempoolTx.position, | ||||
|                 }, | ||||
|                 accelerated: mempoolTx.acceleration || undefined, | ||||
|               }; | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|         if (Object.keys(txs).length) { | ||||
|           response['tracked-txs'] = JSON.stringify(txs); | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       if (client['track-address']) { | ||||
|         const foundTransactions: TransactionExtended[] = Array.from(addressCache[client['track-address']]?.values() || []); | ||||
| 
 | ||||
| @ -1126,6 +1239,7 @@ class WebsocketHandler { | ||||
|   private printLogs(): void { | ||||
|     if (this.wss) { | ||||
|       let numTxSubs = 0; | ||||
|       let numTxsSubs = 0; | ||||
|       let numProjectedSubs = 0; | ||||
|       let numRbfSubs = 0; | ||||
| 
 | ||||
| @ -1133,6 +1247,9 @@ class WebsocketHandler { | ||||
|         if (client['track-tx']) { | ||||
|           numTxSubs++; | ||||
|         } | ||||
|         if (client['track-txs']) { | ||||
|           numTxsSubs++; | ||||
|         } | ||||
|         if (client['track-mempool-block'] != null && client['track-mempool-block'] >= 0) { | ||||
|           numProjectedSubs++; | ||||
|         } | ||||
| @ -1145,7 +1262,7 @@ class WebsocketHandler { | ||||
|       const diff = count - this.numClients; | ||||
|       this.numClients = count; | ||||
|       logger.debug(`${count} websocket clients | ${this.numConnected} connected | ${this.numDisconnected} disconnected | (${diff >= 0 ? '+' : ''}${diff})`); | ||||
|       logger.debug(`websocket subscriptions: track-tx: ${numTxSubs}, track-mempool-block: ${numProjectedSubs} track-rbf: ${numRbfSubs}`); | ||||
|       logger.debug(`websocket subscriptions: track-tx: ${numTxSubs}, track-txs: ${numTxsSubs}, track-mempool-block: ${numProjectedSubs} track-rbf: ${numRbfSubs}`); | ||||
|       this.numConnected = 0; | ||||
|       this.numDisconnected = 0; | ||||
|     } | ||||
|  | ||||
| @ -411,6 +411,22 @@ export interface OptimizedStatistic { | ||||
|   vsizes: number[]; | ||||
| } | ||||
| 
 | ||||
| export interface TxTrackingInfo { | ||||
|   replacedBy?: string, | ||||
|   position?: { block: number, vsize: number, accelerated?: boolean }, | ||||
|   cpfp?: { | ||||
|     ancestors?: Ancestor[], | ||||
|     bestDescendant?: Ancestor | null, | ||||
|     descendants?: Ancestor[] | null, | ||||
|     effectiveFeePerVsize?: number | null, | ||||
|     sigops: number, | ||||
|     adjustedVsize: number, | ||||
|   }, | ||||
|   utxoSpent?: { [vout: number]: { vin: number, txid: string } }, | ||||
|   accelerated?: boolean, | ||||
|   confirmed?: boolean | ||||
| } | ||||
| 
 | ||||
| export interface WebsocketResponse { | ||||
|   action: string; | ||||
|   data: string[]; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user