fix rbf cache eviction logic
This commit is contained in:
		
							parent
							
								
									603a85f06f
								
							
						
					
					
						commit
						29db163af7
					
				@ -1,3 +1,4 @@
 | 
			
		||||
import logger from "../logger";
 | 
			
		||||
import { TransactionExtended, TransactionStripped } from "../mempool.interfaces";
 | 
			
		||||
import bitcoinApi from './bitcoin/bitcoin-api-factory';
 | 
			
		||||
import { Common } from "./common";
 | 
			
		||||
@ -23,10 +24,10 @@ class RbfCache {
 | 
			
		||||
  private dirtyTrees: Set<string> = new Set();
 | 
			
		||||
  private treeMap: Map<string, string> = new Map(); // map of txids to sequence ids
 | 
			
		||||
  private txs: Map<string, TransactionExtended> = new Map();
 | 
			
		||||
  private expiring: Map<string, Date> = new Map();
 | 
			
		||||
  private expiring: Map<string, number> = new Map();
 | 
			
		||||
 | 
			
		||||
  constructor() {
 | 
			
		||||
    setInterval(this.cleanup.bind(this), 1000 * 60 * 60);
 | 
			
		||||
    setInterval(this.cleanup.bind(this), 1000 * 60 * 10);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public add(replaced: TransactionExtended[], newTxExtended: TransactionExtended): void {
 | 
			
		||||
@ -146,6 +147,9 @@ class RbfCache {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public mined(txid): void {
 | 
			
		||||
    if (!this.txs.has(txid)) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    const treeId = this.treeMap.get(txid);
 | 
			
		||||
    if (treeId && this.rbfTrees.has(treeId)) {
 | 
			
		||||
      const tree = this.rbfTrees.get(treeId);
 | 
			
		||||
@ -159,18 +163,21 @@ class RbfCache {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // flag a transaction as removed from the mempool
 | 
			
		||||
  public evict(txid): void {
 | 
			
		||||
    this.expiring.set(txid, new Date(Date.now() + 1000 * 86400)); // 24 hours
 | 
			
		||||
  public evict(txid, fast: boolean = false): void {
 | 
			
		||||
    if (this.txs.has(txid) && (fast || !this.expiring.has(txid))) {
 | 
			
		||||
      this.expiring.set(txid, fast ? Date.now() + (1000 * 60 * 10) : Date.now() + (1000 * 86400)); // 24 hours
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private cleanup(): void {
 | 
			
		||||
    const currentDate = new Date();
 | 
			
		||||
    for (const txid in this.expiring) {
 | 
			
		||||
      if ((this.expiring.get(txid) || 0) < currentDate) {
 | 
			
		||||
    const now = Date.now();
 | 
			
		||||
    for (const txid of this.expiring.keys()) {
 | 
			
		||||
      if ((this.expiring.get(txid) || 0) < now) {
 | 
			
		||||
        this.expiring.delete(txid);
 | 
			
		||||
        this.remove(txid);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    logger.debug(`rbf cache contains ${this.txs.size} txs, ${this.expiring.size} due to expire`);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // remove a transaction & all previous versions from the cache
 | 
			
		||||
@ -237,7 +244,9 @@ class RbfCache {
 | 
			
		||||
      await this.importTree(deflatedTree.root, deflatedTree.root, deflatedTree, this.txs);
 | 
			
		||||
    }
 | 
			
		||||
    expiring.forEach(expiringEntry => {
 | 
			
		||||
      this.expiring.set(expiringEntry[0], expiringEntry[1]);
 | 
			
		||||
      if (this.txs.has(expiringEntry[0])) {
 | 
			
		||||
        this.expiring.set(expiringEntry[0], new Date(expiringEntry[1]).getTime());
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    this.cleanup();
 | 
			
		||||
  }
 | 
			
		||||
@ -269,18 +278,29 @@ class RbfCache {
 | 
			
		||||
 | 
			
		||||
    // check if any transactions in this tree have already been confirmed
 | 
			
		||||
    mined = mined || treeInfo.mined;
 | 
			
		||||
    let exists = mined;
 | 
			
		||||
    if (!mined) {
 | 
			
		||||
      try {
 | 
			
		||||
        const apiTx = await bitcoinApi.$getRawTransaction(txid);
 | 
			
		||||
        if (apiTx) {
 | 
			
		||||
          exists = true;
 | 
			
		||||
        }
 | 
			
		||||
        if (apiTx?.status?.confirmed) {
 | 
			
		||||
          mined = true;
 | 
			
		||||
          this.evict(txid);
 | 
			
		||||
          treeInfo.txMined = true;
 | 
			
		||||
          this.evict(txid, true);
 | 
			
		||||
        }
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        // most transactions do not exist
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // if the root tx is not in the mempool or the blockchain
 | 
			
		||||
    // evict this tree as soon as possible
 | 
			
		||||
    if (root === txid && !exists) {
 | 
			
		||||
      this.evict(txid, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // recursively reconstruct child trees
 | 
			
		||||
    for (const childId of treeInfo.replaces) {
 | 
			
		||||
      const replaced = await this.importTree(root, childId, deflated, txs, mined);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user