mempool/backend/src/api/mempool.ts

146 lines
4.4 KiB
TypeScript
Raw Normal View History

2019-07-21 16:59:47 +02:00
const config = require('../../mempool-config.json');
import bitcoinApi from './bitcoin/electrs-api';
import { MempoolInfo, SimpleTransaction, Transaction } from '../interfaces';
2019-07-21 16:59:47 +02:00
class Mempool {
private mempoolCache: any = {};
private mempoolInfo: MempoolInfo | undefined;
2019-07-21 16:59:47 +02:00
private mempoolChangedCallback: Function | undefined;
private txPerSecondArray: number[] = [];
private txPerSecond: number = 0;
private vBytesPerSecondArray: any[] = [];
private vBytesPerSecond: number = 0;
constructor() {
setInterval(this.updateTxPerSecond.bind(this), 1000);
}
public setMempoolChangedCallback(fn: Function) {
this.mempoolChangedCallback = fn;
}
public getMempool(): { [txid: string]: SimpleTransaction } {
return this.mempoolCache;
2019-07-21 16:59:47 +02:00
}
public setMempool(mempoolData: any) {
this.mempoolCache = mempoolData;
if (this.mempoolChangedCallback && mempoolData) {
this.mempoolChangedCallback(mempoolData);
}
2019-07-21 16:59:47 +02:00
}
2020-02-17 14:39:20 +01:00
public async updateMemPoolInfo() {
try {
this.mempoolInfo = await bitcoinApi.getMempoolInfo();
} catch (err) {
console.log('Error getMempoolInfo', err);
}
}
public getMempoolInfo(): MempoolInfo | undefined {
2019-07-21 16:59:47 +02:00
return this.mempoolInfo;
}
public getTxPerSecond(): number {
return this.txPerSecond;
}
public getVBytesPerSecond(): number {
return this.vBytesPerSecond;
}
public async getRawTransaction(txId: string): Promise<SimpleTransaction | false> {
2019-07-21 16:59:47 +02:00
try {
const transaction: Transaction = await bitcoinApi.getRawTransaction(txId);
return {
txid: transaction.txid,
fee: transaction.fee,
size: transaction.size,
vsize: transaction.weight / 4,
feePerVsize: transaction.fee / (transaction.weight / 4)
};
2019-07-21 16:59:47 +02:00
} catch (e) {
console.log(txId + ' not found');
return false;
}
}
public async updateMempool() {
console.log('Updating mempool');
const start = new Date().getTime();
let hasChange: boolean = false;
let txCount = 0;
try {
const transactions = await bitcoinApi.getRawMempool();
const diff = transactions.length - Object.keys(this.mempoolCache).length;
for (const txid of transactions) {
if (!this.mempoolCache[txid]) {
const transaction = await this.getRawTransaction(txid);
2019-07-21 16:59:47 +02:00
if (transaction) {
this.mempoolCache[txid] = transaction;
2019-07-21 16:59:47 +02:00
txCount++;
this.txPerSecondArray.push(new Date().getTime());
this.vBytesPerSecondArray.push({
unixTime: new Date().getTime(),
vSize: transaction.vsize,
});
hasChange = true;
if (diff > 0) {
console.log('Fetched transaction ' + txCount + ' / ' + diff);
2019-07-21 16:59:47 +02:00
} else {
console.log('Fetched transaction ' + txCount);
2019-07-21 16:59:47 +02:00
}
} else {
console.log('Error finding transaction in mempool.');
}
}
if ((new Date().getTime()) - start > config.MEMPOOL_REFRESH_RATE_MS) {
break;
}
2019-07-21 16:59:47 +02:00
}
// Replace mempool to clear already confirmed transactions
const newMempool: any = {};
2019-07-21 16:59:47 +02:00
transactions.forEach((tx) => {
if (this.mempoolCache[tx]) {
newMempool[tx] = this.mempoolCache[tx];
2019-07-21 16:59:47 +02:00
} else {
hasChange = true;
}
});
this.mempoolCache = newMempool;
2019-07-21 16:59:47 +02:00
if (hasChange && this.mempoolChangedCallback) {
this.mempoolChangedCallback(this.mempoolCache);
2019-07-21 16:59:47 +02:00
}
const end = new Date().getTime();
const time = end - start;
console.log('Mempool updated in ' + time / 1000 + ' seconds');
} catch (err) {
console.log('getRawMempool error.', err);
}
}
private updateTxPerSecond() {
const nowMinusTimeSpan = new Date().getTime() - (1000 * config.TX_PER_SECOND_SPAN_SECONDS);
this.txPerSecondArray = this.txPerSecondArray.filter((unixTime) => unixTime > nowMinusTimeSpan);
this.txPerSecond = this.txPerSecondArray.length / config.TX_PER_SECOND_SPAN_SECONDS || 0;
this.vBytesPerSecondArray = this.vBytesPerSecondArray.filter((data) => data.unixTime > nowMinusTimeSpan);
if (this.vBytesPerSecondArray.length) {
this.vBytesPerSecond = Math.round(
this.vBytesPerSecondArray.map((data) => data.vSize).reduce((a, b) => a + b) / config.TX_PER_SECOND_SPAN_SECONDS
);
}
}
}
export default new Mempool();