103 lines
3.6 KiB
TypeScript
103 lines
3.6 KiB
TypeScript
const config = require('../../mempool-config.json');
|
|
import { ITransaction, IProjectedBlock, IMempool, IProjectedBlockInternal } from '../interfaces';
|
|
|
|
class ProjectedBlocks {
|
|
private transactionsSorted: ITransaction[] = [];
|
|
|
|
constructor() {}
|
|
|
|
public getProjectedBlockFeesForBlock(index: number) {
|
|
const projectedBlock = this.getProjectedBlocksInternal()[index];
|
|
|
|
if (!projectedBlock) {
|
|
throw new Error('No projected block for that index');
|
|
}
|
|
|
|
return projectedBlock.txFeePerVsizes.map((fpv) => {
|
|
return {'fpv': fpv};
|
|
});
|
|
}
|
|
|
|
public updateProjectedBlocks(memPool: IMempool): void {
|
|
const latestMempool = memPool;
|
|
const memPoolArray: ITransaction[] = [];
|
|
for (const i in latestMempool) {
|
|
if (latestMempool.hasOwnProperty(i)) {
|
|
memPoolArray.push(latestMempool[i]);
|
|
}
|
|
}
|
|
memPoolArray.sort((a, b) => b.feePerWeightUnit - a.feePerWeightUnit);
|
|
this.transactionsSorted = memPoolArray.filter((tx) => tx.feePerWeightUnit);
|
|
}
|
|
|
|
public getProjectedBlocks(txId?: string, numberOfBlocks: number = config.DEFAULT_PROJECTED_BLOCKS_AMOUNT): IProjectedBlock[] {
|
|
return this.getProjectedBlocksInternal(numberOfBlocks).map((projectedBlock) => {
|
|
return {
|
|
blockSize: projectedBlock.blockSize,
|
|
blockWeight: projectedBlock.blockWeight,
|
|
nTx: projectedBlock.nTx,
|
|
minFee: projectedBlock.minFee,
|
|
maxFee: projectedBlock.maxFee,
|
|
minWeightFee: projectedBlock.minWeightFee,
|
|
maxWeightFee: projectedBlock.maxWeightFee,
|
|
medianFee: projectedBlock.medianFee,
|
|
fees: projectedBlock.fees,
|
|
hasMytx: txId ? projectedBlock.txIds.some((tx) => tx === txId) : false
|
|
};
|
|
});
|
|
}
|
|
|
|
private getProjectedBlocksInternal(numberOfBlocks: number = config.DEFAULT_PROJECTED_BLOCKS_AMOUNT): IProjectedBlockInternal[] {
|
|
const projectedBlocks: IProjectedBlockInternal[] = [];
|
|
let blockWeight = 0;
|
|
let blockSize = 0;
|
|
let transactions: ITransaction[] = [];
|
|
this.transactionsSorted.forEach((tx) => {
|
|
if (blockWeight + tx.vsize * 4 < 4000000 || projectedBlocks.length === numberOfBlocks) {
|
|
blockWeight += tx.weight || tx.vsize * 4;
|
|
blockSize += tx.size;
|
|
transactions.push(tx);
|
|
} else {
|
|
projectedBlocks.push(this.dataToProjectedBlock(transactions, blockSize, blockWeight));
|
|
blockWeight = 0;
|
|
blockSize = 0;
|
|
transactions = [];
|
|
}
|
|
});
|
|
if (transactions.length) {
|
|
projectedBlocks.push(this.dataToProjectedBlock(transactions, blockSize, blockWeight));
|
|
}
|
|
return projectedBlocks;
|
|
}
|
|
|
|
private dataToProjectedBlock(transactions: ITransaction[], blockSize: number, blockWeight: number): IProjectedBlockInternal {
|
|
return {
|
|
blockSize: blockSize,
|
|
blockWeight: blockWeight,
|
|
nTx: transactions.length,
|
|
minFee: transactions[transactions.length - 1].feePerVsize,
|
|
maxFee: transactions[0].feePerVsize,
|
|
minWeightFee: transactions[transactions.length - 1].feePerWeightUnit,
|
|
maxWeightFee: transactions[0].feePerWeightUnit,
|
|
medianFee: this.median(transactions.map((tx) => tx.feePerVsize)),
|
|
txIds: transactions.map((tx) => tx.txid),
|
|
txFeePerVsizes: transactions.map((tx) => tx.feePerVsize).reverse(),
|
|
fees: transactions.map((tx) => tx.fee).reduce((acc, currValue) => acc + currValue),
|
|
};
|
|
}
|
|
|
|
private median(numbers: number[]) {
|
|
let medianNr = 0;
|
|
const numsLen = numbers.length;
|
|
numbers.sort();
|
|
if (numsLen % 2 === 0) {
|
|
medianNr = (numbers[numsLen / 2 - 1] + numbers[numsLen / 2]) / 2;
|
|
} else {
|
|
medianNr = numbers[(numsLen - 1) / 2];
|
|
}
|
|
return medianNr;
|
|
}
|
|
}
|
|
|
|
export default new ProjectedBlocks();
|