2020-09-25 21:11:30 +02:00
|
|
|
|
import { Transaction, TransactionExtended, TransactionStripped } from '../interfaces';
|
2020-05-24 11:29:30 +02:00
|
|
|
|
|
|
|
|
|
export class Common {
|
|
|
|
|
static median(numbers: number[]) {
|
|
|
|
|
let medianNr = 0;
|
|
|
|
|
const numsLen = numbers.length;
|
|
|
|
|
if (numsLen % 2 === 0) {
|
|
|
|
|
medianNr = (numbers[numsLen / 2 - 1] + numbers[numsLen / 2]) / 2;
|
|
|
|
|
} else {
|
|
|
|
|
medianNr = numbers[(numsLen - 1) / 2];
|
|
|
|
|
}
|
|
|
|
|
return medianNr;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-23 19:20:59 +02:00
|
|
|
|
static getFeesInRange(transactions: TransactionExtended[], rangeLength: number) {
|
2020-05-24 11:29:30 +02:00
|
|
|
|
const arr = [transactions[transactions.length - 1].feePerVsize];
|
|
|
|
|
const chunk = 1 / (rangeLength - 1);
|
|
|
|
|
let itemsToAdd = rangeLength - 2;
|
|
|
|
|
|
|
|
|
|
while (itemsToAdd > 0) {
|
|
|
|
|
arr.push(transactions[Math.floor(transactions.length * chunk * itemsToAdd)].feePerVsize);
|
|
|
|
|
itemsToAdd--;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-23 19:20:59 +02:00
|
|
|
|
arr.push(transactions[0].feePerVsize);
|
2020-05-24 11:29:30 +02:00
|
|
|
|
return arr;
|
|
|
|
|
}
|
2020-06-08 13:55:53 +02:00
|
|
|
|
|
|
|
|
|
static findRbfTransactions(added: TransactionExtended[], deleted: TransactionExtended[]): { [txid: string]: TransactionExtended } {
|
|
|
|
|
const matches: { [txid: string]: TransactionExtended } = {};
|
|
|
|
|
deleted
|
|
|
|
|
// The replaced tx must have at least one input with nSequence < maxint-1 (That’s the opt-in)
|
|
|
|
|
.filter((tx) => tx.vin.some((vin) => vin.sequence < 0xfffffffe))
|
|
|
|
|
.forEach((deletedTx) => {
|
|
|
|
|
const foundMatches = added.find((addedTx) => {
|
|
|
|
|
// The new tx must, absolutely speaking, pay at least as much fee as the replaced tx.
|
|
|
|
|
return addedTx.fee > deletedTx.fee
|
|
|
|
|
// The new transaction must pay more fee per kB than the replaced tx.
|
|
|
|
|
&& addedTx.feePerVsize > deletedTx.feePerVsize
|
|
|
|
|
// Spends one or more of the same inputs
|
|
|
|
|
&& deletedTx.vin.some((deletedVin) =>
|
|
|
|
|
addedTx.vin.some((vin) => vin.txid === deletedVin.txid));
|
|
|
|
|
});
|
|
|
|
|
if (foundMatches) {
|
|
|
|
|
matches[deletedTx.txid] = foundMatches;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return matches;
|
|
|
|
|
}
|
2020-09-25 21:11:30 +02:00
|
|
|
|
|
|
|
|
|
static stripTransaction(tx: TransactionExtended): TransactionStripped {
|
|
|
|
|
return {
|
|
|
|
|
txid: tx.txid,
|
|
|
|
|
fee: tx.fee,
|
|
|
|
|
weight: tx.weight,
|
|
|
|
|
value: tx.vin.reduce((acc, vin) => acc + (vin.prevout ? vin.prevout.value : 0), 0),
|
|
|
|
|
};
|
|
|
|
|
}
|
2020-05-24 11:29:30 +02:00
|
|
|
|
}
|