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