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