Merge pull request #4095 from mempool/mononaut/refactor-address-tracking
Refactor websocket address tracking
This commit is contained in:
		
						commit
						41eecfa7df
					
				@ -198,18 +198,14 @@ class WebsocketHandler {
 | 
				
			|||||||
                matchedAddress = matchedAddress.toLowerCase();
 | 
					                matchedAddress = matchedAddress.toLowerCase();
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
              if (/^04[a-fA-F0-9]{128}$/.test(parsedMessage['track-address'])) {
 | 
					              if (/^04[a-fA-F0-9]{128}$/.test(parsedMessage['track-address'])) {
 | 
				
			||||||
                client['track-address'] = null;
 | 
					                client['track-address'] = '41' + matchedAddress + 'ac';
 | 
				
			||||||
                client['track-scriptpubkey'] = '41' + matchedAddress + 'ac';
 | 
					              } else if (/^(02|03)[a-fA-F0-9]{64}$/.test(parsedMessage['track-address'])) {
 | 
				
			||||||
              } else if (/^|(02|03)[a-fA-F0-9]{64}$/.test(parsedMessage['track-address'])) {
 | 
					                client['track-address'] = '21' + matchedAddress + 'ac';
 | 
				
			||||||
                client['track-address'] = null;
 | 
					 | 
				
			||||||
                client['track-scriptpubkey'] = '21' + matchedAddress + 'ac';
 | 
					 | 
				
			||||||
              } else {
 | 
					              } else {
 | 
				
			||||||
                client['track-address'] = matchedAddress;
 | 
					                client['track-address'] = matchedAddress;
 | 
				
			||||||
                client['track-scriptpubkey'] = null;
 | 
					 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
              client['track-address'] = null;
 | 
					              client['track-address'] = null;
 | 
				
			||||||
              client['track-scriptpubkey'] = null;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -488,6 +484,9 @@ class WebsocketHandler {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // pre-compute address transactions
 | 
				
			||||||
 | 
					    const addressCache = this.makeAddressCache(newTransactions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.wss.clients.forEach(async (client) => {
 | 
					    this.wss.clients.forEach(async (client) => {
 | 
				
			||||||
      if (client.readyState !== WebSocket.OPEN) {
 | 
					      if (client.readyState !== WebSocket.OPEN) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
@ -527,78 +526,13 @@ class WebsocketHandler {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (client['track-address']) {
 | 
					      if (client['track-address']) {
 | 
				
			||||||
        const foundTransactions: TransactionExtended[] = [];
 | 
					        const foundTransactions = Array.from(addressCache[client['track-address']]?.values() || []);
 | 
				
			||||||
 | 
					        // txs may be missing prevouts in non-esplora backends
 | 
				
			||||||
 | 
					        // so fetch the full transactions now
 | 
				
			||||||
 | 
					        const fullTransactions = (config.MEMPOOL.BACKEND !== 'esplora') ? await this.getFullTransactions(foundTransactions) : foundTransactions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (const tx of newTransactions) {
 | 
					        if (fullTransactions.length) {
 | 
				
			||||||
          const someVin = tx.vin.some((vin) => !!vin.prevout && vin.prevout.scriptpubkey_address === client['track-address']);
 | 
					          response['address-transactions'] = JSON.stringify(fullTransactions);
 | 
				
			||||||
          if (someVin) {
 | 
					 | 
				
			||||||
            if (config.MEMPOOL.BACKEND !== 'esplora') {
 | 
					 | 
				
			||||||
              try {
 | 
					 | 
				
			||||||
                const fullTx = await transactionUtils.$getMempoolTransactionExtended(tx.txid, true);
 | 
					 | 
				
			||||||
                foundTransactions.push(fullTx);
 | 
					 | 
				
			||||||
              } catch (e) {
 | 
					 | 
				
			||||||
                logger.debug('Error finding transaction in mempool: ' + (e instanceof Error ? e.message : e));
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
              foundTransactions.push(tx);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          const someVout = tx.vout.some((vout) => vout.scriptpubkey_address === client['track-address']);
 | 
					 | 
				
			||||||
          if (someVout) {
 | 
					 | 
				
			||||||
            if (config.MEMPOOL.BACKEND !== 'esplora') {
 | 
					 | 
				
			||||||
              try {
 | 
					 | 
				
			||||||
                const fullTx = await transactionUtils.$getMempoolTransactionExtended(tx.txid, true);
 | 
					 | 
				
			||||||
                foundTransactions.push(fullTx);
 | 
					 | 
				
			||||||
              } catch (e) {
 | 
					 | 
				
			||||||
                logger.debug('Error finding transaction in mempool: ' + (e instanceof Error ? e.message : e));
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
              foundTransactions.push(tx);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (foundTransactions.length) {
 | 
					 | 
				
			||||||
          response['address-transactions'] = JSON.stringify(foundTransactions);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (client['track-scriptpubkey']) {
 | 
					 | 
				
			||||||
        const foundTransactions: TransactionExtended[] = [];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for (const tx of newTransactions) {
 | 
					 | 
				
			||||||
          const someVin = tx.vin.some((vin) => !!vin.prevout && vin.prevout.scriptpubkey_type === 'p2pk' && vin.prevout.scriptpubkey === client['track-scriptpubkey']);
 | 
					 | 
				
			||||||
          if (someVin) {
 | 
					 | 
				
			||||||
            if (config.MEMPOOL.BACKEND !== 'esplora') {
 | 
					 | 
				
			||||||
              try {
 | 
					 | 
				
			||||||
                const fullTx = await transactionUtils.$getMempoolTransactionExtended(tx.txid, true);
 | 
					 | 
				
			||||||
                foundTransactions.push(fullTx);
 | 
					 | 
				
			||||||
              } catch (e) {
 | 
					 | 
				
			||||||
                logger.debug('Error finding transaction in mempool: ' + (e instanceof Error ? e.message : e));
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
              foundTransactions.push(tx);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          const someVout = tx.vout.some((vout) => vout.scriptpubkey_type === 'p2pk' && vout.scriptpubkey === client['track-scriptpubkey']);
 | 
					 | 
				
			||||||
          if (someVout) {
 | 
					 | 
				
			||||||
            if (config.MEMPOOL.BACKEND !== 'esplora') {
 | 
					 | 
				
			||||||
              try {
 | 
					 | 
				
			||||||
                const fullTx = await transactionUtils.$getMempoolTransactionExtended(tx.txid, true);
 | 
					 | 
				
			||||||
                foundTransactions.push(fullTx);
 | 
					 | 
				
			||||||
              } catch (e) {
 | 
					 | 
				
			||||||
                logger.debug('Error finding transaction in mempool: ' + (e instanceof Error ? e.message : e));
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
              foundTransactions.push(tx);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (foundTransactions.length) {
 | 
					 | 
				
			||||||
          response['address-transactions'] = JSON.stringify(foundTransactions);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -606,7 +540,6 @@ class WebsocketHandler {
 | 
				
			|||||||
        const foundTransactions: TransactionExtended[] = [];
 | 
					        const foundTransactions: TransactionExtended[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        newTransactions.forEach((tx) => {
 | 
					        newTransactions.forEach((tx) => {
 | 
				
			||||||
 | 
					 | 
				
			||||||
          if (client['track-asset'] === Common.nativeAssetId) {
 | 
					          if (client['track-asset'] === Common.nativeAssetId) {
 | 
				
			||||||
            if (tx.vin.some((vin) => !!vin.is_pegin)) {
 | 
					            if (tx.vin.some((vin) => !!vin.is_pegin)) {
 | 
				
			||||||
              foundTransactions.push(tx);
 | 
					              foundTransactions.push(tx);
 | 
				
			||||||
@ -805,6 +738,9 @@ class WebsocketHandler {
 | 
				
			|||||||
    const fees = feeApi.getRecommendedFee();
 | 
					    const fees = feeApi.getRecommendedFee();
 | 
				
			||||||
    const mempoolInfo = memPool.getMempoolInfo();
 | 
					    const mempoolInfo = memPool.getMempoolInfo();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // pre-compute address transactions
 | 
				
			||||||
 | 
					    const addressCache = this.makeAddressCache(transactions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // update init data
 | 
					    // update init data
 | 
				
			||||||
    this.updateSocketDataFields({
 | 
					    this.updateSocketDataFields({
 | 
				
			||||||
      'mempoolInfo': mempoolInfo,
 | 
					      'mempoolInfo': mempoolInfo,
 | 
				
			||||||
@ -867,44 +803,7 @@ class WebsocketHandler {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (client['track-address']) {
 | 
					      if (client['track-address']) {
 | 
				
			||||||
        const foundTransactions: TransactionExtended[] = [];
 | 
					        const foundTransactions: TransactionExtended[] = Array.from(addressCache[client['track-address']]?.values() || []);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        transactions.forEach((tx) => {
 | 
					 | 
				
			||||||
          if (tx.vin && tx.vin.some((vin) => !!vin.prevout && vin.prevout.scriptpubkey_address === client['track-address'])) {
 | 
					 | 
				
			||||||
            foundTransactions.push(tx);
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          if (tx.vout && tx.vout.some((vout) => vout.scriptpubkey_address === client['track-address'])) {
 | 
					 | 
				
			||||||
            foundTransactions.push(tx);
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (foundTransactions.length) {
 | 
					 | 
				
			||||||
          foundTransactions.forEach((tx) => {
 | 
					 | 
				
			||||||
            tx.status = {
 | 
					 | 
				
			||||||
              confirmed: true,
 | 
					 | 
				
			||||||
              block_height: block.height,
 | 
					 | 
				
			||||||
              block_hash: block.id,
 | 
					 | 
				
			||||||
              block_time: block.timestamp,
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
          });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          response['block-transactions'] = JSON.stringify(foundTransactions);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (client['track-scriptpubkey']) {
 | 
					 | 
				
			||||||
        const foundTransactions: TransactionExtended[] = [];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        transactions.forEach((tx) => {
 | 
					 | 
				
			||||||
          if (tx.vin && tx.vin.some((vin) => !!vin.prevout && vin.prevout.scriptpubkey_type === 'p2pk' && vin.prevout.scriptpubkey === client['track-scriptpubkey'])) {
 | 
					 | 
				
			||||||
            foundTransactions.push(tx);
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          if (tx.vout && tx.vout.some((vout) => vout.scriptpubkey_type === 'p2pk' && vout.scriptpubkey === client['track-scriptpubkey'])) {
 | 
					 | 
				
			||||||
            foundTransactions.push(tx);
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (foundTransactions.length) {
 | 
					        if (foundTransactions.length) {
 | 
				
			||||||
          foundTransactions.forEach((tx) => {
 | 
					          foundTransactions.forEach((tx) => {
 | 
				
			||||||
@ -982,6 +881,52 @@ class WebsocketHandler {
 | 
				
			|||||||
        + '}';
 | 
					        + '}';
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private makeAddressCache(transactions: MempoolTransactionExtended[]): { [address: string]: Set<MempoolTransactionExtended> } {
 | 
				
			||||||
 | 
					    const addressCache: { [address: string]: Set<MempoolTransactionExtended> } = {};
 | 
				
			||||||
 | 
					    for (const tx of transactions) {
 | 
				
			||||||
 | 
					      for (const vin of tx.vin) {
 | 
				
			||||||
 | 
					        if (vin?.prevout?.scriptpubkey_address) {
 | 
				
			||||||
 | 
					          if (!addressCache[vin.prevout.scriptpubkey_address]) {
 | 
				
			||||||
 | 
					            addressCache[vin.prevout.scriptpubkey_address] = new Set();
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          addressCache[vin.prevout.scriptpubkey_address].add(tx);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (vin?.prevout?.scriptpubkey) {
 | 
				
			||||||
 | 
					          if (!addressCache[vin.prevout.scriptpubkey]) {
 | 
				
			||||||
 | 
					            addressCache[vin.prevout.scriptpubkey] = new Set();
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          addressCache[vin.prevout.scriptpubkey].add(tx);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      for (const vout of tx.vout) {
 | 
				
			||||||
 | 
					        if (vout?.scriptpubkey_address) {
 | 
				
			||||||
 | 
					          if (!addressCache[vout?.scriptpubkey_address]) {
 | 
				
			||||||
 | 
					            addressCache[vout?.scriptpubkey_address] = new Set();
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          addressCache[vout?.scriptpubkey_address].add(tx);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (vout?.scriptpubkey) {
 | 
				
			||||||
 | 
					          if (!addressCache[vout.scriptpubkey]) {
 | 
				
			||||||
 | 
					            addressCache[vout.scriptpubkey] = new Set();
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          addressCache[vout.scriptpubkey].add(tx);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return addressCache;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private async getFullTransactions(transactions: MempoolTransactionExtended[]): Promise<MempoolTransactionExtended[]> {
 | 
				
			||||||
 | 
					    for (let i = 0; i < transactions.length; i++) {
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        transactions[i] = await transactionUtils.$getMempoolTransactionExtended(transactions[i].txid, true);
 | 
				
			||||||
 | 
					      } catch (e) {
 | 
				
			||||||
 | 
					        logger.debug('Error finding transaction in mempool: ' + (e instanceof Error ? e.message : e));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return transactions;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private printLogs(): void {
 | 
					  private printLogs(): void {
 | 
				
			||||||
    if (this.wss) {
 | 
					    if (this.wss) {
 | 
				
			||||||
      const count = this.wss?.clients?.size || 0;
 | 
					      const count = this.wss?.clients?.size || 0;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user