Merge branch 'master' into nymkappa/bugfix/update-log
This commit is contained in:
@@ -2,7 +2,7 @@ import { IEsploraApi } from './esplora-api.interface';
|
||||
|
||||
export interface AbstractBitcoinApi {
|
||||
$getRawMempool(): Promise<IEsploraApi.Transaction['txid'][]>;
|
||||
$getRawTransaction(txId: string, skipConversion?: boolean, addPrevout?: boolean): Promise<IEsploraApi.Transaction>;
|
||||
$getRawTransaction(txId: string, skipConversion?: boolean, addPrevout?: boolean, lazyPrevouts?: boolean): Promise<IEsploraApi.Transaction>;
|
||||
$getBlockHeightTip(): Promise<number>;
|
||||
$getTxIdsForBlock(hash: string): Promise<string[]>;
|
||||
$getBlockHash(height: number): Promise<string>;
|
||||
|
||||
@@ -31,7 +31,8 @@ class BitcoinApi implements AbstractBitcoinApi {
|
||||
};
|
||||
}
|
||||
|
||||
$getRawTransaction(txId: string, skipConversion = false, addPrevout = false): Promise<IEsploraApi.Transaction> {
|
||||
|
||||
$getRawTransaction(txId: string, skipConversion = false, addPrevout = false, lazyPrevouts = false): Promise<IEsploraApi.Transaction> {
|
||||
// If the transaction is in the mempool we already converted and fetched the fee. Only prevouts are missing
|
||||
const txInMempool = mempool.getMempool()[txId];
|
||||
if (txInMempool && addPrevout) {
|
||||
@@ -46,7 +47,7 @@ class BitcoinApi implements AbstractBitcoinApi {
|
||||
});
|
||||
return transaction;
|
||||
}
|
||||
return this.$convertTransaction(transaction, addPrevout);
|
||||
return this.$convertTransaction(transaction, addPrevout, lazyPrevouts);
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
if (e.message.startsWith('The genesis block coinbase')) {
|
||||
@@ -126,7 +127,7 @@ class BitcoinApi implements AbstractBitcoinApi {
|
||||
const outSpends: IEsploraApi.Outspend[] = [];
|
||||
const tx = await this.$getRawTransaction(txId, true, false);
|
||||
for (let i = 0; i < tx.vout.length; i++) {
|
||||
if (tx.status && tx.status.block_height == 0) {
|
||||
if (tx.status && tx.status.block_height === 0) {
|
||||
outSpends.push({
|
||||
spent: false
|
||||
});
|
||||
@@ -145,7 +146,7 @@ class BitcoinApi implements AbstractBitcoinApi {
|
||||
return this.bitcoindClient.getNetworkHashPs(120, blockHeight);
|
||||
}
|
||||
|
||||
protected async $convertTransaction(transaction: IBitcoinApi.Transaction, addPrevout: boolean): Promise<IEsploraApi.Transaction> {
|
||||
protected async $convertTransaction(transaction: IBitcoinApi.Transaction, addPrevout: boolean, lazyPrevouts = false): Promise<IEsploraApi.Transaction> {
|
||||
let esploraTransaction: IEsploraApi.Transaction = {
|
||||
txid: transaction.txid,
|
||||
version: transaction.version,
|
||||
@@ -192,12 +193,9 @@ class BitcoinApi implements AbstractBitcoinApi {
|
||||
}
|
||||
|
||||
if (addPrevout) {
|
||||
if (transaction.confirmations) {
|
||||
esploraTransaction = await this.$calculateFeeFromInputs(esploraTransaction);
|
||||
} else {
|
||||
esploraTransaction = await this.$appendMempoolFeeData(esploraTransaction);
|
||||
esploraTransaction = await this.$calculateFeeFromInputs(esploraTransaction);
|
||||
}
|
||||
esploraTransaction = await this.$calculateFeeFromInputs(esploraTransaction, false, lazyPrevouts);
|
||||
} else if (!transaction.confirmations) {
|
||||
esploraTransaction = await this.$appendMempoolFeeData(esploraTransaction);
|
||||
}
|
||||
|
||||
return esploraTransaction;
|
||||
@@ -271,20 +269,30 @@ class BitcoinApi implements AbstractBitcoinApi {
|
||||
return this.bitcoindClient.getRawMemPool(true);
|
||||
}
|
||||
|
||||
private async $calculateFeeFromInputs(transaction: IEsploraApi.Transaction): Promise<IEsploraApi.Transaction> {
|
||||
|
||||
private async $calculateFeeFromInputs(transaction: IEsploraApi.Transaction, addPrevout: boolean, lazyPrevouts: boolean): Promise<IEsploraApi.Transaction> {
|
||||
if (transaction.vin[0].is_coinbase) {
|
||||
transaction.fee = 0;
|
||||
return transaction;
|
||||
}
|
||||
let totalIn = 0;
|
||||
for (const vin of transaction.vin) {
|
||||
const innerTx = await this.$getRawTransaction(vin.txid, false, false);
|
||||
vin.prevout = innerTx.vout[vin.vout];
|
||||
this.addInnerScriptsToVin(vin);
|
||||
totalIn += innerTx.vout[vin.vout].value;
|
||||
|
||||
for (let i = 0; i < transaction.vin.length; i++) {
|
||||
if (lazyPrevouts && i > 12) {
|
||||
transaction.vin[i].lazy = true;
|
||||
continue;
|
||||
}
|
||||
const innerTx = await this.$getRawTransaction(transaction.vin[i].txid, false, false);
|
||||
transaction.vin[i].prevout = innerTx.vout[transaction.vin[i].vout];
|
||||
this.addInnerScriptsToVin(transaction.vin[i]);
|
||||
totalIn += innerTx.vout[transaction.vin[i].vout].value;
|
||||
}
|
||||
if (lazyPrevouts && transaction.vin.length > 12) {
|
||||
transaction.fee = -1;
|
||||
} else {
|
||||
const totalOut = transaction.vout.reduce((p, output) => p + output.value, 0);
|
||||
transaction.fee = parseFloat((totalIn - totalOut).toFixed(8));
|
||||
}
|
||||
const totalOut = transaction.vout.reduce((p, output) => p + output.value, 0);
|
||||
transaction.fee = parseFloat((totalIn - totalOut).toFixed(8));
|
||||
return transaction;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ export namespace IEsploraApi {
|
||||
// Elements
|
||||
is_pegin?: boolean;
|
||||
issuance?: Issuance;
|
||||
// Custom
|
||||
lazy?: boolean;
|
||||
}
|
||||
|
||||
interface Issuance {
|
||||
|
||||
@@ -4,7 +4,7 @@ import logger from '../logger';
|
||||
import { Common } from './common';
|
||||
|
||||
class DatabaseMigration {
|
||||
private static currentVersion = 17;
|
||||
private static currentVersion = 18;
|
||||
private queryTimeout = 120000;
|
||||
private statisticsAddedIndexed = false;
|
||||
|
||||
@@ -180,6 +180,10 @@ class DatabaseMigration {
|
||||
if (databaseSchemaVersion < 17 && isBitcoin === true) {
|
||||
await this.$executeQuery('ALTER TABLE `pools` ADD `slug` CHAR(50) NULL');
|
||||
}
|
||||
|
||||
if (databaseSchemaVersion < 18 && isBitcoin === true) {
|
||||
await this.$executeQuery('ALTER TABLE `blocks` ADD INDEX `hash` (`hash`);');
|
||||
}
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ class TransactionUtils {
|
||||
};
|
||||
}
|
||||
|
||||
public async $getTransactionExtended(txId: string, addPrevouts = false): Promise<TransactionExtended> {
|
||||
const transaction: IEsploraApi.Transaction = await bitcoinApi.$getRawTransaction(txId, false, addPrevouts);
|
||||
public async $getTransactionExtended(txId: string, addPrevouts = false, lazyPrevouts = false): Promise<TransactionExtended> {
|
||||
const transaction: IEsploraApi.Transaction = await bitcoinApi.$getRawTransaction(txId, false, addPrevouts, lazyPrevouts);
|
||||
return this.extendTransaction(transaction);
|
||||
}
|
||||
|
||||
|
||||
@@ -645,7 +645,7 @@ class Routes {
|
||||
res.header('Pragma', 'public');
|
||||
res.header('Cache-control', 'public');
|
||||
res.header('X-total-count', blockCount.toString());
|
||||
res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString());
|
||||
res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString());
|
||||
res.json(blockFees);
|
||||
} catch (e) {
|
||||
res.status(500).send(e instanceof Error ? e.message : e);
|
||||
@@ -659,7 +659,7 @@ class Routes {
|
||||
res.header('Pragma', 'public');
|
||||
res.header('Cache-control', 'public');
|
||||
res.header('X-total-count', blockCount.toString());
|
||||
res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString());
|
||||
res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString());
|
||||
res.json(blockRewards);
|
||||
} catch (e) {
|
||||
res.status(500).send(e instanceof Error ? e.message : e);
|
||||
@@ -672,7 +672,7 @@ class Routes {
|
||||
const oldestIndexedBlockTimestamp = await BlocksRepository.$oldestBlockTimestamp();
|
||||
res.header('Pragma', 'public');
|
||||
res.header('Cache-control', 'public');
|
||||
res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString());
|
||||
res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString());
|
||||
res.json({
|
||||
oldestIndexedBlockTimestamp: oldestIndexedBlockTimestamp,
|
||||
blockFeeRates: blockFeeRates,
|
||||
@@ -690,7 +690,7 @@ class Routes {
|
||||
res.header('Pragma', 'public');
|
||||
res.header('Cache-control', 'public');
|
||||
res.header('X-total-count', blockCount.toString());
|
||||
res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString());
|
||||
res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString());
|
||||
res.json({
|
||||
sizes: blockSizes,
|
||||
weights: blockWeights
|
||||
@@ -703,6 +703,7 @@ class Routes {
|
||||
public async getBlock(req: Request, res: Response) {
|
||||
try {
|
||||
const block = await blocks.$getBlock(req.params.hash);
|
||||
res.setHeader('Expires', new Date(Date.now() + 1000 * 600).toUTCString());
|
||||
res.json(block);
|
||||
} catch (e) {
|
||||
res.status(500).send(e instanceof Error ? e.message : e);
|
||||
@@ -722,6 +723,7 @@ class Routes {
|
||||
public async getBlocksExtras(req: Request, res: Response) {
|
||||
try {
|
||||
const height = req.params.height === undefined ? undefined : parseInt(req.params.height, 10);
|
||||
res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString());
|
||||
res.json(await blocks.$getBlocksExtras(height, 15));
|
||||
} catch (e) {
|
||||
res.status(500).send(e instanceof Error ? e.message : e);
|
||||
@@ -776,9 +778,9 @@ class Routes {
|
||||
const endIndex = Math.min(startingIndex + 10, txIds.length);
|
||||
for (let i = startingIndex; i < endIndex; i++) {
|
||||
try {
|
||||
const transaction = await transactionUtils.$getTransactionExtended(txIds[i], true);
|
||||
const transaction = await transactionUtils.$getTransactionExtended(txIds[i], true, true);
|
||||
transactions.push(transaction);
|
||||
loadingIndicators.setProgress('blocktxs-' + req.params.hash, (i + 1) / endIndex * 100);
|
||||
loadingIndicators.setProgress('blocktxs-' + req.params.hash, (i - startingIndex + 1) / (endIndex - startingIndex) * 100);
|
||||
} catch (e) {
|
||||
logger.debug('getBlockTransactions error: ' + (e instanceof Error ? e.message : e));
|
||||
}
|
||||
@@ -1001,6 +1003,7 @@ class Routes {
|
||||
public async $getRewardStats(req: Request, res: Response) {
|
||||
try {
|
||||
const response = await mining.$getRewardStats(parseInt(req.params.blockCount, 10));
|
||||
res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString());
|
||||
res.json(response);
|
||||
} catch (e) {
|
||||
res.status(500).end();
|
||||
|
||||
Reference in New Issue
Block a user