Merge pull request #3719 from mempool/mononaut/fix-rbf-cache-eviction
fix rbf cache eviction logic
This commit is contained in:
commit
a7dff0effe
@ -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