Merge branch 'master' into nymkappa/bugfix/ln-network-history-chart
This commit is contained in:
commit
c23aa67b0c
@ -83,7 +83,7 @@ class NetworkSyncService {
|
|||||||
logger.info(`${progress} nodes updated. ${deletedSockets} sockets deleted`);
|
logger.info(`${progress} nodes updated. ${deletedSockets} sockets deleted`);
|
||||||
|
|
||||||
// If a channel if not present in the graph, mark it as inactive
|
// If a channel if not present in the graph, mark it as inactive
|
||||||
nodesApi.$setNodesInactive(graphNodesPubkeys);
|
await nodesApi.$setNodesInactive(graphNodesPubkeys);
|
||||||
|
|
||||||
if (config.MAXMIND.ENABLED) {
|
if (config.MAXMIND.ENABLED) {
|
||||||
$lookupNodeLocation();
|
$lookupNodeLocation();
|
||||||
@ -121,7 +121,7 @@ class NetworkSyncService {
|
|||||||
logger.info(`${progress} channels updated`);
|
logger.info(`${progress} channels updated`);
|
||||||
|
|
||||||
// If a channel if not present in the graph, mark it as inactive
|
// If a channel if not present in the graph, mark it as inactive
|
||||||
channelsApi.$setChannelsInactive(graphChannelsIds);
|
await channelsApi.$setChannelsInactive(graphChannelsIds);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.err(`Cannot update channel list. Reason: ${(e instanceof Error ? e.message : e)}`);
|
logger.err(`Cannot update channel list. Reason: ${(e instanceof Error ? e.message : e)}`);
|
||||||
}
|
}
|
||||||
@ -285,11 +285,24 @@ class NetworkSyncService {
|
|||||||
for (const channel of channels) {
|
for (const channel of channels) {
|
||||||
let reason = 0;
|
let reason = 0;
|
||||||
// Only Esplora backend can retrieve spent transaction outputs
|
// Only Esplora backend can retrieve spent transaction outputs
|
||||||
const outspends = await bitcoinApi.$getOutspends(channel.closing_transaction_id);
|
try {
|
||||||
|
let outspends: IEsploraApi.Outspend[] | undefined;
|
||||||
|
try {
|
||||||
|
outspends = await bitcoinApi.$getOutspends(channel.closing_transaction_id);
|
||||||
|
} catch (e) {
|
||||||
|
logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/tx/' + channel.closing_transaction_id + '/outspends'}. Reason ${e instanceof Error ? e.message : e}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const lightningScriptReasons: number[] = [];
|
const lightningScriptReasons: number[] = [];
|
||||||
for (const outspend of outspends) {
|
for (const outspend of outspends) {
|
||||||
if (outspend.spent && outspend.txid) {
|
if (outspend.spent && outspend.txid) {
|
||||||
const spendingTx = await bitcoinApi.$getRawTransaction(outspend.txid);
|
let spendingTx: IEsploraApi.Transaction | undefined;
|
||||||
|
try {
|
||||||
|
spendingTx = await bitcoinApi.$getRawTransaction(outspend.txid);
|
||||||
|
} catch (e) {
|
||||||
|
logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/tx/' + outspend.txid}. Reason ${e instanceof Error ? e.message : e}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const lightningScript = this.findLightningScript(spendingTx.vin[outspend.vin || 0]);
|
const lightningScript = this.findLightningScript(spendingTx.vin[outspend.vin || 0]);
|
||||||
lightningScriptReasons.push(lightningScript);
|
lightningScriptReasons.push(lightningScript);
|
||||||
}
|
}
|
||||||
@ -310,7 +323,13 @@ class NetworkSyncService {
|
|||||||
We can detect a commitment transaction (force close) by reading Sequence and Locktime
|
We can detect a commitment transaction (force close) by reading Sequence and Locktime
|
||||||
https://github.com/lightning/bolts/blob/master/03-transactions.md#commitment-transaction
|
https://github.com/lightning/bolts/blob/master/03-transactions.md#commitment-transaction
|
||||||
*/
|
*/
|
||||||
const closingTx = await bitcoinApi.$getRawTransaction(channel.closing_transaction_id);
|
let closingTx: IEsploraApi.Transaction | undefined;
|
||||||
|
try {
|
||||||
|
closingTx = await bitcoinApi.$getRawTransaction(channel.closing_transaction_id);
|
||||||
|
} catch (e) {
|
||||||
|
logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/tx/' + channel.closing_transaction_id}. Reason ${e instanceof Error ? e.message : e}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const sequenceHex: string = closingTx.vin[0].sequence.toString(16);
|
const sequenceHex: string = closingTx.vin[0].sequence.toString(16);
|
||||||
const locktimeHex: string = closingTx.locktime.toString(16);
|
const locktimeHex: string = closingTx.locktime.toString(16);
|
||||||
if (sequenceHex.substring(0, 2) === '80' && locktimeHex.substring(0, 2) === '20') {
|
if (sequenceHex.substring(0, 2) === '80' && locktimeHex.substring(0, 2) === '20') {
|
||||||
@ -324,6 +343,9 @@ class NetworkSyncService {
|
|||||||
logger.debug('Setting closing reason ' + reason + ' for channel: ' + channel.id + '.');
|
logger.debug('Setting closing reason ' + reason + ' for channel: ' + channel.id + '.');
|
||||||
await DB.query(`UPDATE channels SET closing_reason = ? WHERE id = ?`, [reason, channel.id]);
|
await DB.query(`UPDATE channels SET closing_reason = ? WHERE id = ?`, [reason, channel.id]);
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
logger.err(`$runClosedChannelsForensics() failed for channel ${channel.short_id}. Reason: ${e instanceof Error ? e.message : e}`);
|
||||||
|
}
|
||||||
|
|
||||||
++progress;
|
++progress;
|
||||||
const elapsedSeconds = Math.round((new Date().getTime() / 1000) - this.loggerTimer);
|
const elapsedSeconds = Math.round((new Date().getTime() / 1000) - this.loggerTimer);
|
||||||
|
@ -1,129 +1,5 @@
|
|||||||
|
|
||||||
.main-title {
|
|
||||||
position: relative;
|
|
||||||
color: #ffffff91;
|
|
||||||
margin-top: -13px;
|
|
||||||
font-size: 10px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-weight: 500;
|
|
||||||
text-align: center;
|
|
||||||
padding-bottom: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.full-container {
|
.full-container {
|
||||||
padding: 0px 15px;
|
margin-top: 25px;
|
||||||
width: 100%;
|
margin-bottom: 25px;
|
||||||
/* min-height: 500px; */
|
min-height: 100%;
|
||||||
height: calc(100% - 150px);
|
|
||||||
@media (max-width: 992px) {
|
|
||||||
height: 100%;
|
|
||||||
padding-bottom: 100px;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
.chart {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
padding-bottom: 20px;
|
|
||||||
padding-right: 10px;
|
|
||||||
@media (max-width: 992px) {
|
|
||||||
padding-bottom: 25px;
|
|
||||||
}
|
|
||||||
@media (max-width: 829px) {
|
|
||||||
padding-bottom: 50px;
|
|
||||||
}
|
|
||||||
@media (max-width: 767px) {
|
|
||||||
padding-bottom: 25px;
|
|
||||||
}
|
|
||||||
@media (max-width: 629px) {
|
|
||||||
padding-bottom: 55px;
|
|
||||||
}
|
|
||||||
@media (max-width: 567px) {
|
|
||||||
padding-bottom: 55px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
.chart-widget {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
max-height: 270px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.formRadioGroup {
|
|
||||||
margin-top: 6px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
@media (min-width: 991px) {
|
|
||||||
position: relative;
|
|
||||||
top: -65px;
|
|
||||||
}
|
|
||||||
@media (min-width: 830px) and (max-width: 991px) {
|
|
||||||
position: relative;
|
|
||||||
top: 0px;
|
|
||||||
}
|
|
||||||
@media (min-width: 830px) {
|
|
||||||
flex-direction: row;
|
|
||||||
float: right;
|
|
||||||
margin-top: 0px;
|
|
||||||
}
|
|
||||||
.btn-sm {
|
|
||||||
font-size: 9px;
|
|
||||||
@media (min-width: 830px) {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.pool-distribution {
|
|
||||||
min-height: 56px;
|
|
||||||
display: block;
|
|
||||||
@media (min-width: 485px) {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
h5 {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
.item {
|
|
||||||
width: 50%;
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0px auto 20px;
|
|
||||||
&:nth-child(2) {
|
|
||||||
order: 2;
|
|
||||||
@media (min-width: 485px) {
|
|
||||||
order: 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&:nth-child(3) {
|
|
||||||
order: 3;
|
|
||||||
@media (min-width: 485px) {
|
|
||||||
order: 2;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
@media (min-width: 768px) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
@media (min-width: 992px) {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.card-title {
|
|
||||||
font-size: 1rem;
|
|
||||||
color: #4a68b9;
|
|
||||||
}
|
|
||||||
.card-text {
|
|
||||||
font-size: 18px;
|
|
||||||
span {
|
|
||||||
color: #ffffff66;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.skeleton-loader {
|
|
||||||
width: 100%;
|
|
||||||
display: block;
|
|
||||||
max-width: 80px;
|
|
||||||
margin: 15px auto 3px;
|
|
||||||
}
|
}
|
@ -25,7 +25,7 @@ import { ActivatedRoute, ParamMap } from '@angular/router';
|
|||||||
export class NodeStatisticsChartComponent implements OnInit {
|
export class NodeStatisticsChartComponent implements OnInit {
|
||||||
@Input() publicKey: string;
|
@Input() publicKey: string;
|
||||||
@Input() right: number | string = 65;
|
@Input() right: number | string = 65;
|
||||||
@Input() left: number | string = 55;
|
@Input() left: number | string = 45;
|
||||||
@Input() widget = false;
|
@Input() widget = false;
|
||||||
|
|
||||||
miningWindowPreference: string;
|
miningWindowPreference: string;
|
||||||
@ -96,7 +96,7 @@ export class NodeStatisticsChartComponent implements OnInit {
|
|||||||
],
|
],
|
||||||
grid: {
|
grid: {
|
||||||
top: 30,
|
top: 30,
|
||||||
bottom: 70,
|
bottom: 20,
|
||||||
right: this.right,
|
right: this.right,
|
||||||
left: this.left,
|
left: this.left,
|
||||||
},
|
},
|
||||||
|
@ -119,10 +119,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="!error">
|
<div *ngIf="!error">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm">
|
||||||
<app-nodes-channels-map [style]="'nodepage'" [publicKey]="node.public_key"></app-nodes-channels-map>
|
<app-nodes-channels-map [style]="'nodepage'" [publicKey]="node.public_key"></app-nodes-channels-map>
|
||||||
|
</div>
|
||||||
<h2 i18n="lightning.node-history">Node history</h2>
|
<div class="col-sm">
|
||||||
<app-node-statistics-chart [publicKey]="node.public_key"></app-node-statistics-chart>
|
<app-node-statistics-chart [publicKey]="node.public_key"></app-node-statistics-chart>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h2 i18n="lightning.active-channels-map">Active channels map</h2>
|
<h2 i18n="lightning.active-channels-map">Active channels map</h2>
|
||||||
<app-node-channels style="display:block;margin-bottom: 40px" [publicKey]="node.public_key"></app-node-channels>
|
<app-node-channels style="display:block;margin-bottom: 40px" [publicKey]="node.public_key"></app-node-channels>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<div [style]="style === 'widget' ? 'height: 250px' : ''">
|
<div class="map-wrapper" [class]="style">
|
||||||
<div *ngIf="channelsObservable | async">
|
<ng-container *ngIf="channelsObservable | async">
|
||||||
<div *ngIf="chartOptions" [class]="'full-container ' + style + (fitContainer ? ' fit-container' : '')">
|
<div *ngIf="chartOptions" [class]="'full-container ' + style + (fitContainer ? ' fit-container' : '')">
|
||||||
<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">
|
||||||
@ -8,9 +8,8 @@
|
|||||||
<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>
|
||||||
|
|
||||||
<div class="chart" [class]="style" echarts [initOpts]="chartInitOptions" [options]="chartOptions" (chartInit)="onChartInit($event)"
|
<div class="chart" [class]="style" echarts [initOpts]="chartInitOptions" [options]="chartOptions"
|
||||||
(chartFinished)="onChartFinished($event)">
|
(chartInit)="onChartInit($event)" (chartFinished)="onChartFinished($event)">
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="!chartOptions && style === 'nodepage'" style="padding-top: 30px"></div>
|
<div *ngIf="!chartOptions && style === 'nodepage'" style="padding-top: 30px"></div>
|
||||||
@ -19,4 +18,5 @@
|
|||||||
<div class="text-center loading-spinner" [class]="style" *ngIf="isLoading">
|
<div class="text-center loading-spinner" [class]="style" *ngIf="isLoading">
|
||||||
<div class="spinner-border text-light"></div>
|
<div class="spinner-border text-light"></div>
|
||||||
</div>
|
</div>
|
||||||
|
</ng-container>
|
||||||
</div>
|
</div>
|
@ -1,3 +1,15 @@
|
|||||||
|
.map-wrapper {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&.widget {
|
||||||
|
height: 250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.graph {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.card-header {
|
.card-header {
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
@ -12,11 +24,6 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 600px;
|
min-height: 600px;
|
||||||
height: calc(100% - 150px);
|
height: calc(100% - 150px);
|
||||||
|
|
||||||
@media (max-width: 992px) {
|
|
||||||
height: 100%;
|
|
||||||
padding-bottom: 100px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.full-container.nodepage {
|
.full-container.nodepage {
|
||||||
min-height: 400px;
|
min-height: 400px;
|
||||||
@ -27,6 +34,7 @@
|
|||||||
min-height: 400px;
|
min-height: 400px;
|
||||||
margin-top: 25px;
|
margin-top: 25px;
|
||||||
margin-bottom: 25px;
|
margin-bottom: 25px;
|
||||||
|
min-height: 100%;
|
||||||
}
|
}
|
||||||
.full-container.widget {
|
.full-container.widget {
|
||||||
height: 250px;
|
height: 250px;
|
||||||
@ -68,21 +76,21 @@
|
|||||||
min-height: 600px;
|
min-height: 600px;
|
||||||
}
|
}
|
||||||
.chart.nodepage {
|
.chart.nodepage {
|
||||||
min-height: 400px;
|
min-height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding-bottom: 0px;
|
||||||
}
|
}
|
||||||
.chart.channelpage {
|
.chart.channelpage {
|
||||||
min-height: 400px;
|
min-height: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.widget {
|
.widget {
|
||||||
width: 90vw;
|
width: 100%;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
height: 250px;
|
height: 250px;
|
||||||
-webkit-mask: linear-gradient(0deg, #11131f00 5%, #11131fff 25%);
|
-webkit-mask: linear-gradient(0deg, #11131f00 5%, #11131fff 25%);
|
||||||
@media (max-width: 767.98px) {
|
|
||||||
width: 100vw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.widget > .chart {
|
.widget > .chart {
|
||||||
min-height: 250px;
|
min-height: 250px;
|
||||||
|
@ -165,7 +165,7 @@ export class NodesChannelsMap implements OnInit {
|
|||||||
|
|
||||||
if (this.style === 'nodepage' && thisNodeGPS) {
|
if (this.style === 'nodepage' && thisNodeGPS) {
|
||||||
this.center = [thisNodeGPS[0], thisNodeGPS[1]];
|
this.center = [thisNodeGPS[0], thisNodeGPS[1]];
|
||||||
this.zoom = 10;
|
this.zoom = 5;
|
||||||
this.channelWidth = 1;
|
this.channelWidth = 1;
|
||||||
this.channelOpacity = 1;
|
this.channelOpacity = 1;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user