mirror of
https://github.com/mempool/mempool.git
synced 2025-02-22 22:25:34 +01:00
Merge branch 'master' into nymkappa/bugfix/missing-last-data-charts
This commit is contained in:
commit
771d21e410
11 changed files with 55 additions and 58 deletions
|
@ -4,7 +4,7 @@ import logger from '../logger';
|
||||||
import { Common } from './common';
|
import { Common } from './common';
|
||||||
|
|
||||||
class DatabaseMigration {
|
class DatabaseMigration {
|
||||||
private static currentVersion = 34;
|
private static currentVersion = 35;
|
||||||
private queryTimeout = 120000;
|
private queryTimeout = 120000;
|
||||||
private statisticsAddedIndexed = false;
|
private statisticsAddedIndexed = false;
|
||||||
private uniqueLogs: string[] = [];
|
private uniqueLogs: string[] = [];
|
||||||
|
@ -315,6 +315,11 @@ class DatabaseMigration {
|
||||||
if (databaseSchemaVersion < 34 && isBitcoin == true) {
|
if (databaseSchemaVersion < 34 && isBitcoin == true) {
|
||||||
await this.$executeQuery('ALTER TABLE `lightning_stats` ADD clearnet_tor_nodes int(11) NOT NULL DEFAULT "0"');
|
await this.$executeQuery('ALTER TABLE `lightning_stats` ADD clearnet_tor_nodes int(11) NOT NULL DEFAULT "0"');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (databaseSchemaVersion < 35 && isBitcoin == true) {
|
||||||
|
await this.$executeQuery('DELETE from `lightning_stats` WHERE added > "2021-09-19"');
|
||||||
|
await this.$executeQuery('ALTER TABLE `lightning_stats` ADD CONSTRAINT added_unique UNIQUE (added);');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -71,8 +71,11 @@ export async function convertAndmergeBidirectionalChannels(clChannels: any[]): P
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertChannelId(channelId): string {
|
export function convertChannelId(channelId): string {
|
||||||
const s = channelId.split('x').map(part => parseInt(part));
|
if (channelId.indexOf('/') !== -1) {
|
||||||
return BigInt((s[0] << 40) | (s[1] << 16) | s[2]).toString();
|
channelId = channelId.slice(0, -2);
|
||||||
|
}
|
||||||
|
const s = channelId.split('x').map(part => BigInt(part));
|
||||||
|
return ((s[0] << 40n) | (s[1] << 16n) | s[2]).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -430,10 +430,13 @@ class NetworkSyncService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private toIntegerId(id: string): string {
|
private toIntegerId(id: string): string {
|
||||||
if (config.LIGHTNING.BACKEND === 'lnd') {
|
if (config.LIGHTNING.BACKEND === 'cln') {
|
||||||
|
return convertChannelId(id);
|
||||||
|
}
|
||||||
|
else if (config.LIGHTNING.BACKEND === 'lnd') {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
return convertChannelId(id);
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Decodes a channel id returned by lnd as uint64 to a short channel id */
|
/** Decodes a channel id returned by lnd as uint64 to a short channel id */
|
||||||
|
|
|
@ -8,8 +8,8 @@ class LightningStatsUpdater {
|
||||||
public async $startService(): Promise<void> {
|
public async $startService(): Promise<void> {
|
||||||
logger.info('Starting Lightning Stats service');
|
logger.info('Starting Lightning Stats service');
|
||||||
|
|
||||||
// LightningStatsImporter.$run();
|
await this.$runTasks();
|
||||||
this.$runTasks();
|
LightningStatsImporter.$run();
|
||||||
}
|
}
|
||||||
|
|
||||||
private setDateMidnight(date: Date): void {
|
private setDateMidnight(date: Date): void {
|
||||||
|
@ -34,7 +34,7 @@ class LightningStatsUpdater {
|
||||||
const date = new Date();
|
const date = new Date();
|
||||||
this.setDateMidnight(date);
|
this.setDateMidnight(date);
|
||||||
|
|
||||||
logger.info(`Updating latest node stats`);
|
logger.info(`Updating latest networks stats`);
|
||||||
const networkGraph = await lightningApi.$getNetworkGraph();
|
const networkGraph = await lightningApi.$getNetworkGraph();
|
||||||
LightningStatsImporter.computeNetworkStats(date.getTime() / 1000, networkGraph);
|
LightningStatsImporter.computeNetworkStats(date.getTime() / 1000, networkGraph);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<ng-container *ngIf="{ val: network$ | async } as network">
|
<ng-container *ngIf="{ val: network$ | async } as network">
|
||||||
<header>
|
<header>
|
||||||
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
|
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
|
||||||
<a class="navbar-brand" [routerLink]="['/' | relativeUrl]">
|
<a class="navbar-brand" [ngClass]="{'dual-logos': subdomain}" [routerLink]="['/' | relativeUrl]">
|
||||||
<ng-template [ngIf]="subdomain">
|
<ng-template [ngIf]="subdomain">
|
||||||
<div class="subdomain_container">
|
<div class="subdomain_container">
|
||||||
<img [src]="'/api/v1/enterprise/images/' + subdomain + '/logo'" class="subdomain_logo">
|
<img [src]="'/api/v1/enterprise/images/' + subdomain + '/logo'" class="subdomain_logo">
|
||||||
|
|
|
@ -9,6 +9,7 @@ fa-icon {
|
||||||
.navbar {
|
.navbar {
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
min-height: 64px;
|
min-height: 64px;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
li.nav-item {
|
li.nav-item {
|
||||||
|
@ -86,6 +87,13 @@ li.nav-item {
|
||||||
height: 65px;
|
height: 65px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.navbar-brand.dual-logos {
|
||||||
|
justify-content: space-between;
|
||||||
|
@media (max-width: 767.98px) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nav {
|
nav {
|
||||||
box-shadow: 0px 0px 15px 0px #000;
|
box-shadow: 0px 0px 15px 0px #000;
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,9 +102,7 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br>
|
<div class="input-group mt-3" *ngIf="!error && node.socketsObject.length">
|
||||||
|
|
||||||
<div class="input-group mb-3" *ngIf="!error && node.socketsObject.length">
|
|
||||||
<div class="d-inline-block" ngbDropdown #myDrop="ngbDropdown"
|
<div class="d-inline-block" ngbDropdown #myDrop="ngbDropdown"
|
||||||
*ngIf="node.socketsObject.length > 1; else noDropdown">
|
*ngIf="node.socketsObject.length > 1; else noDropdown">
|
||||||
<button class="btn btn-secondary dropdown-toggle" type="button" aria-expanded="false" ngbDropdownAnchor
|
<button class="btn btn-secondary dropdown-toggle" type="button" aria-expanded="false" ngbDropdownAnchor
|
||||||
|
@ -133,24 +131,16 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br>
|
<app-nodes-channels-map *ngIf="!error" [style]="'nodepage'" [publicKey]="node.public_key"></app-nodes-channels-map>
|
||||||
|
|
||||||
<app-node-statistics-chart [publicKey]="node.public_key" *ngIf="!error"></app-node-statistics-chart>
|
<app-node-statistics-chart [publicKey]="node.public_key" *ngIf="!error"></app-node-statistics-chart>
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<div class="d-flex justify-content-between" *ngIf="!error">
|
<div class="d-flex justify-content-between" *ngIf="!error">
|
||||||
<h2><span i18n="lightning.all-channels">All channels</span> ({{ channelsListStatus === 'open' ? node.opened_channel_count : node.closed_channel_count }})</h2>
|
<h2>Channels ({{ channelsListStatus === 'open' ? node.opened_channel_count : node.closed_channel_count }})</h2>
|
||||||
<div class="d-flex justify-content-end">
|
|
||||||
<app-toggle [textLeft]="'List'" [textRight]="'Map'" (toggleStatusChanged)="channelsListModeChange($event)"></app-toggle>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<app-nodes-channels-map *ngIf="channelsListMode === 'map' && !error" [style]="'nodepage'" [publicKey]="node.public_key">
|
<app-channels-list *ngIf="!error" [publicKey]="node.public_key"
|
||||||
</app-nodes-channels-map>
|
|
||||||
<app-channels-list *ngIf="channelsListMode === 'list' && !error" [publicKey]="node.public_key"
|
|
||||||
(channelsStatusChangedEvent)="onChannelsListStatusChanged($event)"></app-channels-list>
|
(channelsStatusChangedEvent)="onChannelsListStatusChanged($event)"></app-channels-list>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
|
@ -19,7 +19,6 @@ export class NodeComponent implements OnInit {
|
||||||
publicKey$: Observable<string>;
|
publicKey$: Observable<string>;
|
||||||
selectedSocketIndex = 0;
|
selectedSocketIndex = 0;
|
||||||
qrCodeVisible = false;
|
qrCodeVisible = false;
|
||||||
channelsListMode = 'list';
|
|
||||||
channelsListStatus: string;
|
channelsListStatus: string;
|
||||||
error: Error;
|
error: Error;
|
||||||
publicKey: string;
|
publicKey: string;
|
||||||
|
@ -83,14 +82,6 @@ export class NodeComponent implements OnInit {
|
||||||
this.selectedSocketIndex = index;
|
this.selectedSocketIndex = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
channelsListModeChange(toggle) {
|
|
||||||
if (toggle === true) {
|
|
||||||
this.channelsListMode = 'map';
|
|
||||||
} else {
|
|
||||||
this.channelsListMode = 'list';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onChannelsListStatusChanged(e) {
|
onChannelsListStatusChanged(e) {
|
||||||
this.channelsListStatus = e;
|
this.channelsListStatus = e;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,6 @@
|
||||||
<div *ngIf="style === 'graph'" class="card-header">
|
<div *ngIf="style === 'graph'" class="card-header">
|
||||||
<div class="d-flex d-md-block align-items-baseline" style="margin-bottom: -5px">
|
<div class="d-flex d-md-block align-items-baseline" style="margin-bottom: -5px">
|
||||||
<span i18n="lightning.nodes-channels-world-map">Lightning nodes channels world map</span>
|
<span i18n="lightning.nodes-channels-world-map">Lightning nodes channels world map</span>
|
||||||
<button class="btn p-0 pl-2" style="margin: 0 0 4px 0px">
|
|
||||||
<fa-icon [icon]="['fas', 'download']" [fixedWidth]="true" (click)="onSaveChart()"></fa-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<small style="color: #ffffff66" i18n="lightning.tor-nodes-excluded">(Tor nodes excluded)</small>
|
<small style="color: #ffffff66" i18n="lightning.tor-nodes-excluded">(Tor nodes excluded)</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -20,7 +20,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.full-container.nodepage {
|
.full-container.nodepage {
|
||||||
margin-top: 50px;
|
margin-top: 25px;
|
||||||
|
margin-bottom: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.full-container.widget {
|
.full-container.widget {
|
||||||
|
|
|
@ -3,7 +3,6 @@ import { SeoService } from 'src/app/services/seo.service';
|
||||||
import { ApiService } from 'src/app/services/api.service';
|
import { ApiService } from 'src/app/services/api.service';
|
||||||
import { Observable, switchMap, tap, zip } from 'rxjs';
|
import { Observable, switchMap, tap, zip } from 'rxjs';
|
||||||
import { AssetsService } from 'src/app/services/assets.service';
|
import { AssetsService } from 'src/app/services/assets.service';
|
||||||
import { download } from 'src/app/shared/graphs.utils';
|
|
||||||
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
|
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
|
||||||
import { RelativeUrlPipe } from 'src/app/shared/pipes/relative-url/relative-url.pipe';
|
import { RelativeUrlPipe } from 'src/app/shared/pipes/relative-url/relative-url.pipe';
|
||||||
import { StateService } from 'src/app/services/state.service';
|
import { StateService } from 'src/app/services/state.service';
|
||||||
|
@ -21,6 +20,7 @@ export class NodesChannelsMap implements OnInit, OnDestroy {
|
||||||
@Input() publicKey: string | undefined;
|
@Input() publicKey: string | undefined;
|
||||||
|
|
||||||
observable$: Observable<any>;
|
observable$: Observable<any>;
|
||||||
|
center: number[] | undefined = undefined;
|
||||||
|
|
||||||
chartInstance = undefined;
|
chartInstance = undefined;
|
||||||
chartOptions: EChartsOption = {};
|
chartOptions: EChartsOption = {};
|
||||||
|
@ -42,6 +42,8 @@ export class NodesChannelsMap implements OnInit, OnDestroy {
|
||||||
ngOnDestroy(): void {}
|
ngOnDestroy(): void {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
this.center = this.style === 'widget' ? [0, 0, -10] : undefined;
|
||||||
|
|
||||||
if (this.style === 'graph') {
|
if (this.style === 'graph') {
|
||||||
this.seoService.setTitle($localize`Lightning nodes channels world map`);
|
this.seoService.setTitle($localize`Lightning nodes channels world map`);
|
||||||
}
|
}
|
||||||
|
@ -52,13 +54,21 @@ export class NodesChannelsMap implements OnInit, OnDestroy {
|
||||||
return zip(
|
return zip(
|
||||||
this.assetsService.getWorldMapJson$,
|
this.assetsService.getWorldMapJson$,
|
||||||
this.apiService.getChannelsGeo$(params.get('public_key') ?? undefined),
|
this.apiService.getChannelsGeo$(params.get('public_key') ?? undefined),
|
||||||
|
[params.get('public_key') ?? undefined]
|
||||||
).pipe(tap((data) => {
|
).pipe(tap((data) => {
|
||||||
registerMap('world', data[0]);
|
registerMap('world', data[0]);
|
||||||
|
|
||||||
const channelsLoc = [];
|
const channelsLoc = [];
|
||||||
const nodes = [];
|
const nodes = [];
|
||||||
const nodesPubkeys = {};
|
const nodesPubkeys = {};
|
||||||
|
let thisNodeGPS: number[] | undefined = undefined;
|
||||||
for (const channel of data[1]) {
|
for (const channel of data[1]) {
|
||||||
|
if (!thisNodeGPS && data[2] === channel[0]) {
|
||||||
|
thisNodeGPS = [channel[2], channel[3]];
|
||||||
|
} else if (!thisNodeGPS && data[2] === channel[4]) {
|
||||||
|
thisNodeGPS = [channel[6], channel[7]];
|
||||||
|
}
|
||||||
|
|
||||||
channelsLoc.push([[channel[2], channel[3]], [channel[6], channel[7]]]);
|
channelsLoc.push([[channel[2], channel[3]], [channel[6], channel[7]]]);
|
||||||
if (!nodesPubkeys[channel[0]]) {
|
if (!nodesPubkeys[channel[0]]) {
|
||||||
nodes.push({
|
nodes.push({
|
||||||
|
@ -77,6 +87,13 @@ export class NodesChannelsMap implements OnInit, OnDestroy {
|
||||||
nodesPubkeys[channel[4]] = true;
|
nodesPubkeys[channel[4]] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this.style === 'nodepage' && thisNodeGPS) {
|
||||||
|
// 1ML 0217890e3aad8d35bc054f43acc00084b25229ecff0ab68debd82883ad65ee8266
|
||||||
|
// New York GPS [-74.0068, 40.7123]
|
||||||
|
// Map center [-20.55, 0, -9.85]
|
||||||
|
this.center = [thisNodeGPS[0] * -20.55 / -74.0068, 0, thisNodeGPS[1] * -9.85 / 40.7123];
|
||||||
|
}
|
||||||
|
|
||||||
this.prepareChartOptions(nodes, channelsLoc);
|
this.prepareChartOptions(nodes, channelsLoc);
|
||||||
}));
|
}));
|
||||||
})
|
})
|
||||||
|
@ -111,10 +128,10 @@ export class NodesChannelsMap implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
viewControl: {
|
viewControl: {
|
||||||
center: this.style === 'widget' ? [0, 0, -10] : undefined,
|
center: this.center,
|
||||||
minDistance: 1,
|
minDistance: 1,
|
||||||
maxDistance: 60,
|
maxDistance: 60,
|
||||||
distance: this.style === 'widget' ? 22 : 60,
|
distance: this.style === 'widget' ? 22 : this.style === 'nodepage' ? 22 : 60,
|
||||||
alpha: 90,
|
alpha: 90,
|
||||||
rotateSensitivity: 0,
|
rotateSensitivity: 0,
|
||||||
panSensitivity: this.style === 'widget' ? 0 : 1,
|
panSensitivity: this.style === 'widget' ? 0 : 1,
|
||||||
|
@ -204,22 +221,4 @@ export class NodesChannelsMap implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onSaveChart() {
|
|
||||||
// @ts-ignore
|
|
||||||
const prevBottom = this.chartOptions.grid.bottom;
|
|
||||||
const now = new Date();
|
|
||||||
// @ts-ignore
|
|
||||||
this.chartOptions.grid.bottom = 30;
|
|
||||||
this.chartOptions.backgroundColor = '#11131f';
|
|
||||||
this.chartInstance.setOption(this.chartOptions);
|
|
||||||
download(this.chartInstance.getDataURL({
|
|
||||||
pixelRatio: 2,
|
|
||||||
excludeComponents: ['dataZoom'],
|
|
||||||
}), `lightning-nodes-heatmap-clearnet-${Math.round(now.getTime() / 1000)}.svg`);
|
|
||||||
// @ts-ignore
|
|
||||||
this.chartOptions.grid.bottom = prevBottom;
|
|
||||||
this.chartOptions.backgroundColor = 'none';
|
|
||||||
this.chartInstance.setOption(this.chartOptions);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue