keep cached RBF info for 24 hours after tx leaves the mempool
This commit is contained in:
parent
0481f57304
commit
d778530620
@ -595,7 +595,7 @@ class BitcoinRoutes {
|
|||||||
private async getRbfHistory(req: Request, res: Response) {
|
private async getRbfHistory(req: Request, res: Response) {
|
||||||
try {
|
try {
|
||||||
const result = rbfCache.getReplaces(req.params.txId);
|
const result = rbfCache.getReplaces(req.params.txId);
|
||||||
res.json(result?.txids || []);
|
res.json(result || []);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
res.status(500).send(e instanceof Error ? e.message : e);
|
res.status(500).send(e instanceof Error ? e.message : e);
|
||||||
}
|
}
|
||||||
|
@ -236,6 +236,7 @@ class Mempool {
|
|||||||
const lazyDeleteAt = this.mempoolCache[tx].deleteAfter;
|
const lazyDeleteAt = this.mempoolCache[tx].deleteAfter;
|
||||||
if (lazyDeleteAt && lazyDeleteAt < now) {
|
if (lazyDeleteAt && lazyDeleteAt < now) {
|
||||||
delete this.mempoolCache[tx];
|
delete this.mempoolCache[tx];
|
||||||
|
rbfCache.evict(tx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,46 +1,29 @@
|
|||||||
import { TransactionExtended } from "../mempool.interfaces";
|
import { TransactionExtended } from "../mempool.interfaces";
|
||||||
|
|
||||||
export interface CachedRbf {
|
|
||||||
txid: string;
|
|
||||||
expires: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CachedRbfs {
|
|
||||||
txids: string[];
|
|
||||||
expires: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
class RbfCache {
|
class RbfCache {
|
||||||
private replacedby: { [txid: string]: CachedRbf; } = {};
|
private replacedBy: { [txid: string]: string; } = {};
|
||||||
private replaces: { [txid: string]: CachedRbfs } = {};
|
private replaces: { [txid: string]: string[] } = {};
|
||||||
private txs: { [txid: string]: TransactionExtended } = {};
|
private txs: { [txid: string]: TransactionExtended } = {};
|
||||||
|
private expiring: { [txid: string]: Date } = {};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
setInterval(this.cleanup.bind(this), 1000 * 60 * 60);
|
setInterval(this.cleanup.bind(this), 1000 * 60 * 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
public add(replacedTx: TransactionExtended, newTxId: string): void {
|
public add(replacedTx: TransactionExtended, newTxId: string): void {
|
||||||
const expiry = new Date(Date.now() + 1000 * 604800); // 1 week
|
this.replacedBy[replacedTx.txid] = newTxId;
|
||||||
this.replacedby[replacedTx.txid] = {
|
|
||||||
expires: expiry,
|
|
||||||
txid: newTxId,
|
|
||||||
};
|
|
||||||
this.txs[replacedTx.txid] = replacedTx;
|
this.txs[replacedTx.txid] = replacedTx;
|
||||||
if (!this.replaces[newTxId]) {
|
if (!this.replaces[newTxId]) {
|
||||||
this.replaces[newTxId] = {
|
this.replaces[newTxId] = [];
|
||||||
txids: [],
|
|
||||||
expires: expiry,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
this.replaces[newTxId].txids.push(replacedTx.txid);
|
this.replaces[newTxId].push(replacedTx.txid);
|
||||||
this.replaces[newTxId].expires = expiry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getReplacedBy(txId: string): CachedRbf | undefined {
|
public getReplacedBy(txId: string): string | undefined {
|
||||||
return this.replacedby[txId];
|
return this.replacedBy[txId];
|
||||||
}
|
}
|
||||||
|
|
||||||
public getReplaces(txId: string): CachedRbfs | undefined {
|
public getReplaces(txId: string): string[] | undefined {
|
||||||
return this.replaces[txId];
|
return this.replaces[txId];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,17 +31,32 @@ class RbfCache {
|
|||||||
return this.txs[txId];
|
return this.txs[txId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// flag a transaction as removed from the mempool
|
||||||
|
public evict(txid): void {
|
||||||
|
this.expiring[txid] = new Date(Date.now() + 1000 * 86400); // 24 hours
|
||||||
|
}
|
||||||
|
|
||||||
private cleanup(): void {
|
private cleanup(): void {
|
||||||
const currentDate = new Date();
|
const currentDate = new Date();
|
||||||
for (const c in this.replacedby) {
|
for (const txid in this.expiring) {
|
||||||
if (this.replacedby[c].expires < currentDate) {
|
if (this.expiring[txid] < currentDate) {
|
||||||
delete this.replacedby[c];
|
delete this.expiring[txid];
|
||||||
delete this.txs[c];
|
this.remove(txid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const c in this.replaces) {
|
}
|
||||||
if (this.replaces[c].expires < currentDate) {
|
|
||||||
delete this.replaces[c];
|
// remove a transaction & all previous versions from the cache
|
||||||
|
private remove(txid): void {
|
||||||
|
// don't remove a transaction while a newer version remains in the mempool
|
||||||
|
if (this.replaces[txid] && !this.replacedBy[txid]) {
|
||||||
|
const replaces = this.replaces[txid];
|
||||||
|
delete this.replaces[txid];
|
||||||
|
for (const tx of replaces) {
|
||||||
|
// recursively remove prior versions from the cache
|
||||||
|
delete this.replacedBy[tx];
|
||||||
|
delete this.txs[tx];
|
||||||
|
this.remove(tx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,10 +58,10 @@ class WebsocketHandler {
|
|||||||
client['track-tx'] = parsedMessage['track-tx'];
|
client['track-tx'] = parsedMessage['track-tx'];
|
||||||
// Client is telling the transaction wasn't found
|
// Client is telling the transaction wasn't found
|
||||||
if (parsedMessage['watch-mempool']) {
|
if (parsedMessage['watch-mempool']) {
|
||||||
const rbfCacheTx = rbfCache.getReplacedBy(client['track-tx']);
|
const rbfCacheTxid = rbfCache.getReplacedBy(client['track-tx']);
|
||||||
if (rbfCacheTx) {
|
if (rbfCacheTxid) {
|
||||||
response['txReplaced'] = {
|
response['txReplaced'] = {
|
||||||
txid: rbfCacheTx.txid,
|
txid: rbfCacheTxid,
|
||||||
};
|
};
|
||||||
client['track-tx'] = null;
|
client['track-tx'] = null;
|
||||||
} else {
|
} else {
|
||||||
@ -467,6 +467,7 @@ class WebsocketHandler {
|
|||||||
for (const txId of txIds) {
|
for (const txId of txIds) {
|
||||||
delete _memPool[txId];
|
delete _memPool[txId];
|
||||||
removed.push(txId);
|
removed.push(txId);
|
||||||
|
rbfCache.evict(txId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.MEMPOOL.ADVANCED_GBT_MEMPOOL) {
|
if (config.MEMPOOL.ADVANCED_GBT_MEMPOOL) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user