Compare commits

...

17 Commits

Author SHA1 Message Date
hunicus
9508bb88ef Add i18n for lightning footer link 2023-03-07 02:06:52 -05:00
softsimon
aef26097ec Merge pull request #3223 from mempool/mononaut/fix-cpfp-table-widths
Fix overlapping columns in cpfp table on small screens
2023-03-04 17:56:35 +09:00
softsimon
2ed4e5bb6e Merge pull request #3222 from mempool/simon/incoming-transactions-progress-color
Correct incoming transaction progress colors
2023-03-04 16:55:44 +09:00
softsimon
fdcf4ce501 Merge pull request #3220 from mempool/mononaut/fiat-decimals
drop decimal places from large fiat values
2023-03-04 16:55:05 +09:00
wiz
0223846f91 Merge pull request #3122 from mempool/nymkappa/bugfix/cleanup-mining-states
Remove mining db stats - replaced by runtime state variable
2023-03-04 16:54:10 +09:00
wiz
1192d4fbd4 Merge branch 'master' into nymkappa/bugfix/cleanup-mining-states 2023-03-04 16:46:44 +09:00
wiz
027603acf7 Merge pull request #2995 from mempool/simon/bisq-search-bar-fix
Bisq markets search bar fix
2023-03-04 16:22:04 +09:00
wiz
152b8e8a7d Merge branch 'master' into simon/bisq-search-bar-fix 2023-03-04 16:06:46 +09:00
softsimon
375219242c Merge pull request #3224 from mempool/ops/fix-bisq-address-prefix-api
ops: Add missing /api/address-prefix nginx route for bisq
2023-03-04 16:06:23 +09:00
wiz
5fb4eac4b7 ops: Add missing /api/address-prefix nginx route for bisq 2023-03-04 15:53:49 +09:00
softsimon
f8624020e8 Bisq markets search bar fix
fixes #2986
2023-03-04 15:35:08 +09:00
Mononaut
269dcb2b16 Fix overlapping columns in cpfp table on small screens 2023-03-04 00:22:50 -06:00
softsimon
ec2e7a46eb Correct incoming transaction progress colors
fixes #3216
2023-03-04 15:19:56 +09:00
Mononaut
a37bcfec65 drop decimal places from large fiat values 2023-03-04 00:10:47 -06:00
nymkappa
e0c3c732d1 Fix incorrect db schema version in db migration script 2023-03-04 10:55:27 +09:00
nymkappa
622929831e Merge branch 'master' into nymkappa/bugfix/cleanup-mining-states 2023-03-04 10:54:02 +09:00
nymkappa
8aebcf3e57 Remove mining db stats - replaced by runtime state variable 2023-03-01 16:42:26 +09:00
12 changed files with 61 additions and 68 deletions

View File

@@ -7,7 +7,7 @@ import cpfpRepository from '../repositories/CpfpRepository';
import { RowDataPacket } from 'mysql2'; import { RowDataPacket } from 'mysql2';
class DatabaseMigration { class DatabaseMigration {
private static currentVersion = 57; private static currentVersion = 58;
private queryTimeout = 3600_000; private queryTimeout = 3600_000;
private statisticsAddedIndexed = false; private statisticsAddedIndexed = false;
private uniqueLogs: string[] = []; private uniqueLogs: string[] = [];
@@ -505,6 +505,11 @@ class DatabaseMigration {
await this.$executeQuery(`ALTER TABLE nodes MODIFY updated_at datetime NULL`); await this.$executeQuery(`ALTER TABLE nodes MODIFY updated_at datetime NULL`);
await this.updateToSchemaVersion(57); await this.updateToSchemaVersion(57);
} }
if (databaseSchemaVersion < 58) {
// We only run some migration queries for this version
await this.updateToSchemaVersion(58);
}
} }
/** /**
@@ -632,6 +637,11 @@ class DatabaseMigration {
queries.push(`INSERT INTO state(name, number, string) VALUES ('last_weekly_hashrates_indexing', 0, NULL)`); queries.push(`INSERT INTO state(name, number, string) VALUES ('last_weekly_hashrates_indexing', 0, NULL)`);
} }
if (version < 58) {
queries.push(`DELETE FROM state WHERE name = 'last_hashrates_indexing'`);
queries.push(`DELETE FROM state WHERE name = 'last_weekly_hashrates_indexing'`);
}
return queries; return queries;
} }

View File

@@ -15,10 +15,9 @@ import { bitcoinCoreApi } from '../bitcoin/bitcoin-api-factory';
import { IEsploraApi } from '../bitcoin/esplora-api.interface'; import { IEsploraApi } from '../bitcoin/esplora-api.interface';
class Mining { class Mining {
blocksPriceIndexingRunning = false; private blocksPriceIndexingRunning = false;
public lastHashrateIndexingDate: number | null = null;
constructor() { public lastWeeklyHashrateIndexingDate: number | null = null;
}
/** /**
* Get historical block predictions match rate * Get historical block predictions match rate
@@ -178,13 +177,14 @@ class Mining {
*/ */
public async $generatePoolHashrateHistory(): Promise<void> { public async $generatePoolHashrateHistory(): Promise<void> {
const now = new Date(); const now = new Date();
const lastestRunDate = await HashratesRepository.$getLatestRun('last_weekly_hashrates_indexing');
// Run only if: // Run only if:
// * lastestRunDate is set to 0 (node backend restart, reorg) // * this.lastWeeklyHashrateIndexingDate is set to null (node backend restart, reorg)
// * we started a new week (around Monday midnight) // * we started a new week (around Monday midnight)
const runIndexing = lastestRunDate === 0 || now.getUTCDay() === 1 && lastestRunDate !== now.getUTCDate(); const runIndexing = this.lastWeeklyHashrateIndexingDate === null ||
now.getUTCDay() === 1 && this.lastWeeklyHashrateIndexingDate !== now.getUTCDate();
if (!runIndexing) { if (!runIndexing) {
logger.debug(`Pool hashrate history indexing is up to date, nothing to do`, logger.tags.mining);
return; return;
} }
@@ -266,7 +266,7 @@ class Mining {
++indexedThisRun; ++indexedThisRun;
++totalIndexed; ++totalIndexed;
} }
await HashratesRepository.$setLatestRun('last_weekly_hashrates_indexing', new Date().getUTCDate()); this.lastWeeklyHashrateIndexingDate = new Date().getUTCDate();
if (newlyIndexed > 0) { if (newlyIndexed > 0) {
logger.notice(`Weekly mining pools hashrates indexing completed: indexed ${newlyIndexed}`, logger.tags.mining); logger.notice(`Weekly mining pools hashrates indexing completed: indexed ${newlyIndexed}`, logger.tags.mining);
} else { } else {
@@ -285,9 +285,9 @@ class Mining {
*/ */
public async $generateNetworkHashrateHistory(): Promise<void> { public async $generateNetworkHashrateHistory(): Promise<void> {
// We only run this once a day around midnight // We only run this once a day around midnight
const latestRunDate = await HashratesRepository.$getLatestRun('last_hashrates_indexing'); const today = new Date().getUTCDate();
const now = new Date().getUTCDate(); if (today === this.lastHashrateIndexingDate) {
if (now === latestRunDate) { logger.debug(`Network hashrate history indexing is up to date, nothing to do`, logger.tags.mining);
return; return;
} }
@@ -371,7 +371,7 @@ class Mining {
newlyIndexed += hashrates.length; newlyIndexed += hashrates.length;
await HashratesRepository.$saveHashrates(hashrates); await HashratesRepository.$saveHashrates(hashrates);
await HashratesRepository.$setLatestRun('last_hashrates_indexing', new Date().getUTCDate()); this.lastHashrateIndexingDate = new Date().getUTCDate();
if (newlyIndexed > 0) { if (newlyIndexed > 0) {
logger.notice(`Daily network hashrate indexing completed: indexed ${newlyIndexed} days`, logger.tags.mining); logger.notice(`Daily network hashrate indexing completed: indexed ${newlyIndexed} days`, logger.tags.mining);
} else { } else {

View File

@@ -87,9 +87,6 @@ class Server {
await databaseMigration.$blocksReindexingTruncate(); await databaseMigration.$blocksReindexingTruncate();
} }
await databaseMigration.$initializeOrMigrateDatabase(); await databaseMigration.$initializeOrMigrateDatabase();
if (Common.indexingEnabled()) {
await indexer.$resetHashratesIndexingState();
}
} catch (e) { } catch (e) {
throw new Error(e instanceof Error ? e.message : 'Error'); throw new Error(e instanceof Error ? e.message : 'Error');
} }

View File

@@ -3,7 +3,6 @@ import blocks from './api/blocks';
import mempool from './api/mempool'; import mempool from './api/mempool';
import mining from './api/mining/mining'; import mining from './api/mining/mining';
import logger from './logger'; import logger from './logger';
import HashratesRepository from './repositories/HashratesRepository';
import bitcoinClient from './api/bitcoin/bitcoin-client'; import bitcoinClient from './api/bitcoin/bitcoin-client';
import priceUpdater from './tasks/price-updater'; import priceUpdater from './tasks/price-updater';
import PricesRepository from './repositories/PricesRepository'; import PricesRepository from './repositories/PricesRepository';
@@ -131,7 +130,6 @@ class Indexer {
this.runSingleTask('blocksPrices'); this.runSingleTask('blocksPrices');
await mining.$indexDifficultyAdjustments(); await mining.$indexDifficultyAdjustments();
await this.$resetHashratesIndexingState(); // TODO - Remove this as it's not efficient
await mining.$generateNetworkHashrateHistory(); await mining.$generateNetworkHashrateHistory();
await mining.$generatePoolHashrateHistory(); await mining.$generatePoolHashrateHistory();
await blocks.$generateBlocksSummariesDatabase(); await blocks.$generateBlocksSummariesDatabase();
@@ -150,16 +148,6 @@ class Indexer {
logger.debug(`Indexing completed. Next run planned at ${new Date(new Date().getTime() + runEvery).toUTCString()}`); logger.debug(`Indexing completed. Next run planned at ${new Date(new Date().getTime() + runEvery).toUTCString()}`);
setTimeout(() => this.reindex(), runEvery); setTimeout(() => this.reindex(), runEvery);
} }
async $resetHashratesIndexingState(): Promise<void> {
try {
await HashratesRepository.$setLatestRun('last_hashrates_indexing', 0);
await HashratesRepository.$setLatestRun('last_weekly_hashrates_indexing', 0);
} catch (e) {
logger.err(`Cannot reset hashrate indexing timestamps. Reason: ` + (e instanceof Error ? e.message : e));
throw e;
}
}
} }
export default new Indexer(); export default new Indexer();

View File

@@ -1,5 +1,6 @@
import { escape } from 'mysql2'; import { escape } from 'mysql2';
import { Common } from '../api/common'; import { Common } from '../api/common';
import mining from '../api/mining/mining';
import DB from '../database'; import DB from '../database';
import logger from '../logger'; import logger from '../logger';
import PoolsRepository from './PoolsRepository'; import PoolsRepository from './PoolsRepository';
@@ -177,20 +178,6 @@ class HashratesRepository {
} }
} }
/**
* Set latest run timestamp
*/
public async $setLatestRun(key: string, val: number) {
const query = `UPDATE state SET number = ? WHERE name = ?`;
try {
await DB.query(query, [val, key]);
} catch (e) {
logger.err(`Cannot set last indexing run for ${key}. Reason: ` + (e instanceof Error ? e.message : e));
throw e;
}
}
/** /**
* Get latest run timestamp * Get latest run timestamp
*/ */
@@ -222,8 +209,8 @@ class HashratesRepository {
await DB.query(`DELETE FROM hashrates WHERE hashrate_timestamp = ?`, [row.timestamp]); await DB.query(`DELETE FROM hashrates WHERE hashrate_timestamp = ?`, [row.timestamp]);
} }
// Re-run the hashrate indexing to fill up missing data // Re-run the hashrate indexing to fill up missing data
await this.$setLatestRun('last_hashrates_indexing', 0); mining.lastHashrateIndexingDate = null;
await this.$setLatestRun('last_weekly_hashrates_indexing', 0); mining.lastWeeklyHashrateIndexingDate = null;
} catch (e) { } catch (e) {
logger.err('Cannot delete latest hashrates data points. Reason: ' + (e instanceof Error ? e.message : e)); logger.err('Cannot delete latest hashrates data points. Reason: ' + (e instanceof Error ? e.message : e));
} }
@@ -238,8 +225,8 @@ class HashratesRepository {
try { try {
await DB.query(`DELETE FROM hashrates WHERE hashrate_timestamp >= FROM_UNIXTIME(?)`, [timestamp]); await DB.query(`DELETE FROM hashrates WHERE hashrate_timestamp >= FROM_UNIXTIME(?)`, [timestamp]);
// Re-run the hashrate indexing to fill up missing data // Re-run the hashrate indexing to fill up missing data
await this.$setLatestRun('last_hashrates_indexing', 0); mining.lastHashrateIndexingDate = null;
await this.$setLatestRun('last_weekly_hashrates_indexing', 0); mining.lastWeeklyHashrateIndexingDate = null;
} catch (e) { } catch (e) {
logger.err('Cannot delete latest hashrates data points. Reason: ' + (e instanceof Error ? e.message : e)); logger.err('Cannot delete latest hashrates data points. Reason: ' + (e instanceof Error ? e.message : e));
} }

View File

@@ -107,7 +107,13 @@ export class SearchFormComponent implements OnInit {
}))), }))),
); );
}), }),
tap((result: any[]) => { map((result: any[]) => {
if (this.network === 'bisq') {
result[0] = result[0].map((address: string) => 'B' + address);
}
return result;
}),
tap(() => {
this.isTypeaheading$.next(false); this.isTypeaheading$.next(false);
}) })
); );
@@ -126,7 +132,7 @@ export class SearchFormComponent implements OnInit {
] ]
).pipe( ).pipe(
map((latestData) => { map((latestData) => {
const searchText = latestData[0]; let searchText = latestData[0];
if (!searchText.length) { if (!searchText.length) {
return { return {
searchText: '', searchText: '',
@@ -144,15 +150,15 @@ export class SearchFormComponent implements OnInit {
const addressPrefixSearchResults = result[0]; const addressPrefixSearchResults = result[0];
const lightningResults = result[1]; const lightningResults = result[1];
if (this.network === 'bisq') {
return searchText.map((address: string) => 'B' + address);
}
const matchesBlockHeight = this.regexBlockheight.test(searchText); const matchesBlockHeight = this.regexBlockheight.test(searchText);
const matchesTxId = this.regexTransaction.test(searchText) && !this.regexBlockhash.test(searchText); const matchesTxId = this.regexTransaction.test(searchText) && !this.regexBlockhash.test(searchText);
const matchesBlockHash = this.regexBlockhash.test(searchText); const matchesBlockHash = this.regexBlockhash.test(searchText);
const matchesAddress = this.regexAddress.test(searchText); const matchesAddress = this.regexAddress.test(searchText);
if (matchesAddress && this.network === 'bisq') {
searchText = 'B' + searchText;
}
return { return {
searchText: searchText, searchText: searchText,
hashQuickMatch: +(matchesBlockHeight || matchesBlockHash || matchesTxId || matchesAddress), hashQuickMatch: +(matchesBlockHeight || matchesBlockHash || matchesTxId || matchesAddress),

View File

@@ -204,6 +204,12 @@
.txids { .txids {
width: 60%; width: 60%;
} }
@media (max-width: 500px) {
.txids {
width: 40%;
}
}
} }
.tx-list { .tx-list {

View File

@@ -250,7 +250,7 @@
</span> </span>
<ng-template #inSync> <ng-template #inSync>
<div class="progress inc-tx-progress-bar"> <div class="progress inc-tx-progress-bar">
<div class="progress-bar" role="progressbar" [ngStyle]="{'width': mempoolInfoData.value.progressWidth, 'background-color': mempoolInfoData.value.progressColor}">&nbsp;</div> <div class="progress-bar {{ mempoolInfoData.value.progressColor }}" role="progressbar" [ngStyle]="{'width': mempoolInfoData.value.progressWidth}">&nbsp;</div>
<div class="progress-text">&lrm;{{ mempoolInfoData.value.vBytesPerSecond | ceil | number }} <ng-container i18n="shared.vbytes-per-second|vB/s">vB/s</ng-container></div> <div class="progress-text">&lrm;{{ mempoolInfoData.value.vBytesPerSecond | ceil | number }} <ng-container i18n="shared.vbytes-per-second|vB/s">vB/s</ng-container></div>
</div> </div>
</ng-template> </ng-template>

View File

@@ -78,21 +78,12 @@ export class DashboardComponent implements OnInit, OnDestroy {
map(([mempoolInfo, vbytesPerSecond]) => { map(([mempoolInfo, vbytesPerSecond]) => {
const percent = Math.round((Math.min(vbytesPerSecond, this.vBytesPerSecondLimit) / this.vBytesPerSecondLimit) * 100); const percent = Math.round((Math.min(vbytesPerSecond, this.vBytesPerSecondLimit) / this.vBytesPerSecondLimit) * 100);
let progressColor = '#7CB342'; let progressColor = 'bg-success';
if (vbytesPerSecond > 1667) { if (vbytesPerSecond > 1667) {
progressColor = '#FDD835'; progressColor = 'bg-warning';
}
if (vbytesPerSecond > 2000) {
progressColor = '#FFB300';
}
if (vbytesPerSecond > 2500) {
progressColor = '#FB8C00';
} }
if (vbytesPerSecond > 3000) { if (vbytesPerSecond > 3000) {
progressColor = '#F4511E'; progressColor = 'bg-danger';
}
if (vbytesPerSecond > 3500) {
progressColor = '#D81B60';
} }
const mempoolSizePercentage = (mempoolInfo.usage / mempoolInfo.maxmempool * 100); const mempoolSizePercentage = (mempoolInfo.usage / mempoolInfo.maxmempool * 100);

View File

@@ -98,10 +98,10 @@
| |
<a [routerLink]="['/privacy-policy']" i18n="shared.privacy-policy|Privacy Policy">Privacy Policy</a> <a [routerLink]="['/privacy-policy']" i18n="shared.privacy-policy|Privacy Policy">Privacy Policy</a>
| |
<a *ngIf="officialMempoolSpace" [routerLink]="['/lightning/group/the-mempool-open-source-project' | relativeUrl]">Connect to our nodes</a> <a *ngIf="officialMempoolSpace" [routerLink]="['/lightning/group/the-mempool-open-source-project' | relativeUrl]" i18n="shared.connect-lightning-node|Link for users to see Lightning nodes run by mempool.space they can connect to">Connect to our nodes</a>
<a *ngIf="!officialMempoolSpace" [routerLink]="['/tx/push' | relativeUrl]" i18n="shared.broadcast-transaction|Broadcast Transaction">Broadcast Transaction</a> <a *ngIf="!officialMempoolSpace" [routerLink]="['/tx/push' | relativeUrl]" i18n="shared.broadcast-transaction|Broadcast Transaction">Broadcast Transaction</a>
</div> </div>
<br> <br>
</div> </div>

View File

@@ -23,6 +23,10 @@ export class FiatCurrencyPipe implements PipeTransform {
const digits = args[0] || 1; const digits = args[0] || 1;
const currency = args[1] || this.currency || 'USD'; const currency = args[1] || this.currency || 'USD';
return new Intl.NumberFormat(this.locale, { style: 'currency', currency }).format(num); if (num >= 1000) {
return new Intl.NumberFormat(this.locale, { style: 'currency', currency, maximumFractionDigits: 0 }).format(num);
} else {
return new Intl.NumberFormat(this.locale, { style: 'currency', currency }).format(num);
}
} }
} }

View File

@@ -9,6 +9,10 @@ location /api/tx/ {
rewrite ^/api/(.*) /$1 break; rewrite ^/api/(.*) /$1 break;
try_files /dev/null @esplora-api-cache-disabled; try_files /dev/null @esplora-api-cache-disabled;
} }
location /api/address-prefix/ {
rewrite ^/api/(.*) /$1 break;
try_files /dev/null @esplora-api-cache-disabled;
}
# rewrite APIs to match what backend expects # rewrite APIs to match what backend expects
location /api/currencies { location /api/currencies {