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 { 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