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();
 | 
			
		||||
              }
 | 
			
		||||
              if (/^04[a-fA-F0-9]{128}$/.test(parsedMessage['track-address'])) {
 | 
			
		||||
                client['track-address'] = null;
 | 
			
		||||
                client['track-scriptpubkey'] = '41' + matchedAddress + 'ac';
 | 
			
		||||
              } else if (/^|(02|03)[a-fA-F0-9]{64}$/.test(parsedMessage['track-address'])) {
 | 
			
		||||
                client['track-address'] = null;
 | 
			
		||||
                client['track-scriptpubkey'] = '21' + matchedAddress + 'ac';
 | 
			
		||||
                client['track-address'] = '41' + matchedAddress + 'ac';
 | 
			
		||||
              } else if (/^(02|03)[a-fA-F0-9]{64}$/.test(parsedMessage['track-address'])) {
 | 
			
		||||
                client['track-address'] = '21' + matchedAddress + 'ac';
 | 
			
		||||
              } else {
 | 
			
		||||
                client['track-address'] = matchedAddress;
 | 
			
		||||
                client['track-scriptpubkey'] = null;
 | 
			
		||||
              }
 | 
			
		||||
            } else {
 | 
			
		||||
              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) => {
 | 
			
		||||
      if (client.readyState !== WebSocket.OPEN) {
 | 
			
		||||
        return;
 | 
			
		||||
@ -527,78 +526,13 @@ class WebsocketHandler {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      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) {
 | 
			
		||||
          const someVin = tx.vin.some((vin) => !!vin.prevout && vin.prevout.scriptpubkey_address === client['track-address']);
 | 
			
		||||
          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);
 | 
			
		||||
        if (fullTransactions.length) {
 | 
			
		||||
          response['address-transactions'] = JSON.stringify(fullTransactions);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -606,7 +540,6 @@ class WebsocketHandler {
 | 
			
		||||
        const foundTransactions: TransactionExtended[] = [];
 | 
			
		||||
 | 
			
		||||
        newTransactions.forEach((tx) => {
 | 
			
		||||
 | 
			
		||||
          if (client['track-asset'] === Common.nativeAssetId) {
 | 
			
		||||
            if (tx.vin.some((vin) => !!vin.is_pegin)) {
 | 
			
		||||
              foundTransactions.push(tx);
 | 
			
		||||
@ -805,6 +738,9 @@ class WebsocketHandler {
 | 
			
		||||
    const fees = feeApi.getRecommendedFee();
 | 
			
		||||
    const mempoolInfo = memPool.getMempoolInfo();
 | 
			
		||||
 | 
			
		||||
    // pre-compute address transactions
 | 
			
		||||
    const addressCache = this.makeAddressCache(transactions);
 | 
			
		||||
 | 
			
		||||
    // update init data
 | 
			
		||||
    this.updateSocketDataFields({
 | 
			
		||||
      'mempoolInfo': mempoolInfo,
 | 
			
		||||
@ -867,44 +803,7 @@ class WebsocketHandler {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (client['track-address']) {
 | 
			
		||||
        const foundTransactions: TransactionExtended[] = [];
 | 
			
		||||
 | 
			
		||||
        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);
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
        const foundTransactions: TransactionExtended[] = Array.from(addressCache[client['track-address']]?.values() || []);
 | 
			
		||||
 | 
			
		||||
        if (foundTransactions.length) {
 | 
			
		||||
          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 {
 | 
			
		||||
    if (this.wss) {
 | 
			
		||||
      const count = this.wss?.clients?.size || 0;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user