use bulk /txs endpoint to check cached rbf tx status
This commit is contained in:
		
							parent
							
								
									2339a0771e
								
							
						
					
					
						commit
						38909cfc42
					
				@ -3,6 +3,7 @@ import { IEsploraApi } from './esplora-api.interface';
 | 
			
		||||
export interface AbstractBitcoinApi {
 | 
			
		||||
  $getRawMempool(): Promise<IEsploraApi.Transaction['txid'][]>;
 | 
			
		||||
  $getRawTransaction(txId: string, skipConversion?: boolean, addPrevout?: boolean, lazyPrevouts?: boolean): Promise<IEsploraApi.Transaction>;
 | 
			
		||||
  $getRawTransactions(txids: string[]): Promise<IEsploraApi.Transaction[]>;
 | 
			
		||||
  $getMempoolTransactions(txids: string[]): Promise<IEsploraApi.Transaction[]>;
 | 
			
		||||
  $getAllMempoolTransactions(lastTxid: string);
 | 
			
		||||
  $getTransactionHex(txId: string): Promise<string>;
 | 
			
		||||
 | 
			
		||||
@ -60,6 +60,10 @@ class BitcoinApi implements AbstractBitcoinApi {
 | 
			
		||||
      });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  $getRawTransactions(txids: string[]): Promise<IEsploraApi.Transaction[]> {
 | 
			
		||||
    throw new Error('Method getRawTransactions not supported by the Bitcoin RPC API.');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  $getMempoolTransactions(txids: string[]): Promise<IEsploraApi.Transaction[]> {
 | 
			
		||||
    throw new Error('Method getMempoolTransactions not supported by the Bitcoin RPC API.');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -213,6 +213,10 @@ class ElectrsApi implements AbstractBitcoinApi {
 | 
			
		||||
    return this.failoverRouter.$get<IEsploraApi.Transaction>('/tx/' + txId);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async $getRawTransactions(txids: string[]): Promise<IEsploraApi.Transaction[]> {
 | 
			
		||||
    return this.$postWrapper<IEsploraApi.Transaction[]>(config.ESPLORA.REST_API_URL + '/txs', txids, 'json');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async $getMempoolTransactions(txids: string[]): Promise<IEsploraApi.Transaction[]> {
 | 
			
		||||
    return this.failoverRouter.$post<IEsploraApi.Transaction[]>('/internal/mempool/txs', txids, 'json');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@ import config from "../config";
 | 
			
		||||
import logger from "../logger";
 | 
			
		||||
import { MempoolTransactionExtended, TransactionStripped } from "../mempool.interfaces";
 | 
			
		||||
import bitcoinApi from './bitcoin/bitcoin-api-factory';
 | 
			
		||||
import { IEsploraApi } from "./bitcoin/esplora-api.interface";
 | 
			
		||||
import { Common } from "./common";
 | 
			
		||||
import redisCache from "./redis-cache";
 | 
			
		||||
 | 
			
		||||
@ -383,6 +384,7 @@ class RbfCache {
 | 
			
		||||
      });
 | 
			
		||||
      logger.debug(`loaded ${txs.length} txs, ${trees.length} trees into rbf cache, ${expiring.length} due to expire, ${this.staleCount} were stale`);
 | 
			
		||||
      this.staleCount = 0;
 | 
			
		||||
      await this.checkTrees();
 | 
			
		||||
      this.cleanup();
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      logger.err('failed to restore RBF cache: ' + (e instanceof Error ? e.message : e));
 | 
			
		||||
@ -481,6 +483,57 @@ class RbfCache {
 | 
			
		||||
    return tree;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async checkTrees(): Promise<void> {
 | 
			
		||||
    const found: { [txid: string]: boolean } = {};
 | 
			
		||||
    const txids = Array.from(this.txs.values()).map(tx => tx.txid).filter(txid => {
 | 
			
		||||
      return !this.expiring.has(txid) && !this.getRbfTree(txid)?.mined;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const processTxs = (txs: IEsploraApi.Transaction[]): void => {
 | 
			
		||||
      for (const tx of txs) {
 | 
			
		||||
        found[tx.txid] = true;
 | 
			
		||||
        if (tx.status?.confirmed) {
 | 
			
		||||
          const tree = this.getRbfTree(tx.txid);
 | 
			
		||||
          if (tree) {
 | 
			
		||||
            this.setTreeMined(tree, tx.txid);
 | 
			
		||||
            tree.mined = true;
 | 
			
		||||
            this.evict(tx.txid, false);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (config.MEMPOOL.BACKEND === 'esplora') {
 | 
			
		||||
      const sliceLength = 10000;
 | 
			
		||||
      for (let i = 0; i < Math.ceil(txids.length / sliceLength); i++) {
 | 
			
		||||
        const slice = txids.slice(i * sliceLength, (i + 1) * sliceLength);
 | 
			
		||||
        try {
 | 
			
		||||
          const txs = await bitcoinApi.$getRawTransactions(slice);
 | 
			
		||||
          processTxs(txs);
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
          logger.err('failed to fetch some cached rbf transactions');
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      const txs: IEsploraApi.Transaction[] = [];
 | 
			
		||||
      for (const txid of txids) {
 | 
			
		||||
        try {
 | 
			
		||||
          const tx = await bitcoinApi.$getRawTransaction(txid, true, false);
 | 
			
		||||
          txs.push(tx);
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
          // some 404s are expected, so continue quietly
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      processTxs(txs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (const txid of txids) {
 | 
			
		||||
      if (!found[txid]) {
 | 
			
		||||
        this.evict(txid, false);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public getLatestRbfSummary(): ReplacementInfo[] {
 | 
			
		||||
    const rbfList = this.getRbfTrees(false);
 | 
			
		||||
    return rbfList.slice(0, 6).map(rbfTree => {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user