mirror of
https://github.com/mempool/mempool.git
synced 2024-11-20 02:11:49 +01:00
Merge branch 'master' into nymkappa/bugfix/remove-1mb-node-capacity
This commit is contained in:
commit
a14565e288
@ -5,7 +5,7 @@ class NodesApi {
|
|||||||
public async $getNode(public_key: string): Promise<any> {
|
public async $getNode(public_key: string): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const query = `
|
const query = `
|
||||||
SELECT nodes.*, geo_names_as.names as as_organization, geo_names_city.names as city,
|
SELECT nodes.*, geo_names_iso.names as iso_code, geo_names_as.names as as_organization, geo_names_city.names as city,
|
||||||
geo_names_country.names as country, geo_names_subdivision.names as subdivision,
|
geo_names_country.names as country, geo_names_subdivision.names as subdivision,
|
||||||
(SELECT Count(*)
|
(SELECT Count(*)
|
||||||
FROM channels
|
FROM channels
|
||||||
@ -24,6 +24,7 @@ class NodesApi {
|
|||||||
LEFT JOIN geo_names geo_names_city on geo_names_city.id = city_id
|
LEFT JOIN geo_names geo_names_city on geo_names_city.id = city_id
|
||||||
LEFT JOIN geo_names geo_names_subdivision on geo_names_subdivision.id = subdivision_id
|
LEFT JOIN geo_names geo_names_subdivision on geo_names_subdivision.id = subdivision_id
|
||||||
LEFT JOIN geo_names geo_names_country on geo_names_country.id = country_id
|
LEFT JOIN geo_names geo_names_country on geo_names_country.id = country_id
|
||||||
|
LEFT JOIN geo_names geo_names_iso ON geo_names_iso.id = nodes.country_id AND geo_names_iso.type = 'country_iso_code'
|
||||||
WHERE public_key = ?
|
WHERE public_key = ?
|
||||||
`;
|
`;
|
||||||
const [rows]: any = await DB.query(query, [public_key, public_key, public_key, public_key, public_key, public_key, public_key, public_key, public_key]);
|
const [rows]: any = await DB.query(query, [public_key, public_key, public_key, public_key, public_key, public_key, public_key, public_key, public_key]);
|
||||||
|
@ -5,9 +5,9 @@ const P2SH_P2WSH_COST = 35 * 4; // the WU cost for the non-witness part of P2SH
|
|||||||
|
|
||||||
export function calcSegwitFeeGains(tx: Transaction) {
|
export function calcSegwitFeeGains(tx: Transaction) {
|
||||||
// calculated in weight units
|
// calculated in weight units
|
||||||
let realizedBech32Gains = 0;
|
let realizedSegwitGains = 0;
|
||||||
let potentialBech32Gains = 0;
|
let potentialSegwitGains = 0;
|
||||||
let potentialP2shGains = 0;
|
let potentialP2shSegwitGains = 0;
|
||||||
let potentialTaprootGains = 0;
|
let potentialTaprootGains = 0;
|
||||||
let realizedTaprootGains = 0;
|
let realizedTaprootGains = 0;
|
||||||
|
|
||||||
@ -24,31 +24,33 @@ export function calcSegwitFeeGains(tx: Transaction) {
|
|||||||
const isP2tr = vin.prevout.scriptpubkey_type === 'v1_p2tr';
|
const isP2tr = vin.prevout.scriptpubkey_type === 'v1_p2tr';
|
||||||
|
|
||||||
const op = vin.scriptsig ? vin.scriptsig_asm.split(' ')[0] : null;
|
const op = vin.scriptsig ? vin.scriptsig_asm.split(' ')[0] : null;
|
||||||
const isP2sh2Wpkh = isP2sh && !!vin.witness && op === 'OP_PUSHBYTES_22';
|
const isP2shP2Wpkh = isP2sh && !!vin.witness && op === 'OP_PUSHBYTES_22';
|
||||||
const isP2sh2Wsh = isP2sh && !!vin.witness && op === 'OP_PUSHBYTES_34';
|
const isP2shP2Wsh = isP2sh && !!vin.witness && op === 'OP_PUSHBYTES_34';
|
||||||
|
|
||||||
switch (true) {
|
switch (true) {
|
||||||
// Native Segwit - P2WPKH/P2WSH (Bech32)
|
// Native Segwit - P2WPKH/P2WSH/P2TR
|
||||||
case isP2wpkh:
|
case isP2wpkh:
|
||||||
case isP2wsh:
|
case isP2wsh:
|
||||||
case isP2tr:
|
case isP2tr:
|
||||||
// maximal gains: the scriptSig is moved entirely to the witness part
|
// maximal gains: the scriptSig is moved entirely to the witness part
|
||||||
realizedBech32Gains += witnessSize(vin) * 3;
|
// if taproot is used savings are 42 WU higher because it produces smaller signatures and doesn't require a pubkey in the witness
|
||||||
|
// this number is explained above `realizedTaprootGains += 42;`
|
||||||
|
realizedSegwitGains += (witnessSize(vin) + (isP2tr ? 42 : 0)) * 3;
|
||||||
// XXX P2WSH output creation is more expensive, should we take this into consideration?
|
// XXX P2WSH output creation is more expensive, should we take this into consideration?
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Backward compatible Segwit - P2SH-P2WPKH
|
// Backward compatible Segwit - P2SH-P2WPKH
|
||||||
case isP2sh2Wpkh:
|
case isP2shP2Wpkh:
|
||||||
// the scriptSig is moved to the witness, but we have extra 21 extra non-witness bytes (48 WU)
|
// the scriptSig is moved to the witness, but we have extra 21 extra non-witness bytes (84 WU)
|
||||||
realizedBech32Gains += witnessSize(vin) * 3 - P2SH_P2WPKH_COST;
|
realizedSegwitGains += witnessSize(vin) * 3 - P2SH_P2WPKH_COST;
|
||||||
potentialBech32Gains += P2SH_P2WPKH_COST;
|
potentialSegwitGains += P2SH_P2WPKH_COST;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Backward compatible Segwit - P2SH-P2WSH
|
// Backward compatible Segwit - P2SH-P2WSH
|
||||||
case isP2sh2Wsh:
|
case isP2shP2Wsh:
|
||||||
// the scriptSig is moved to the witness, but we have extra 35 extra non-witness bytes
|
// the scriptSig is moved to the witness, but we have extra 35 extra non-witness bytes (140 WU)
|
||||||
realizedBech32Gains += witnessSize(vin) * 3 - P2SH_P2WSH_COST;
|
realizedSegwitGains += witnessSize(vin) * 3 - P2SH_P2WSH_COST;
|
||||||
potentialBech32Gains += P2SH_P2WSH_COST;
|
potentialSegwitGains += P2SH_P2WSH_COST;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Non-segwit P2PKH/P2SH/P2PK/bare multisig
|
// Non-segwit P2PKH/P2SH/P2PK/bare multisig
|
||||||
@ -56,9 +58,13 @@ export function calcSegwitFeeGains(tx: Transaction) {
|
|||||||
case isP2sh:
|
case isP2sh:
|
||||||
case isP2pk:
|
case isP2pk:
|
||||||
case isBareMultisig: {
|
case isBareMultisig: {
|
||||||
const fullGains = scriptSigSize(vin) * 3;
|
let fullGains = scriptSigSize(vin) * 3;
|
||||||
potentialBech32Gains += fullGains;
|
if (isBareMultisig) {
|
||||||
potentialP2shGains += fullGains - (isP2pkh ? P2SH_P2WPKH_COST : P2SH_P2WSH_COST);
|
// a _bare_ multisig has the keys in the output script, but P2SH and P2WSH require them to be in the scriptSig/scriptWitness
|
||||||
|
fullGains -= vin.prevout.scriptpubkey.length / 2;
|
||||||
|
}
|
||||||
|
potentialSegwitGains += fullGains;
|
||||||
|
potentialP2shSegwitGains += fullGains - (isP2pkh ? P2SH_P2WPKH_COST : P2SH_P2WSH_COST);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,11 +85,11 @@ export function calcSegwitFeeGains(tx: Transaction) {
|
|||||||
// TODO maybe add some complex scripts that are specified somewhere, so that size is known, such as lightning scripts
|
// TODO maybe add some complex scripts that are specified somewhere, so that size is known, such as lightning scripts
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const script = isP2sh2Wsh || isP2wsh ? vin.inner_witnessscript_asm : vin.inner_redeemscript_asm;
|
const script = isP2shP2Wsh || isP2wsh ? vin.inner_witnessscript_asm : vin.inner_redeemscript_asm;
|
||||||
let replacementSize: number;
|
let replacementSize: number;
|
||||||
if (
|
if (
|
||||||
// single sig
|
// single sig
|
||||||
isP2pk || isP2pkh || isP2wpkh || isP2sh2Wpkh ||
|
isP2pk || isP2pkh || isP2wpkh || isP2shP2Wpkh ||
|
||||||
// multisig
|
// multisig
|
||||||
isBareMultisig || parseMultisigScript(script)
|
isBareMultisig || parseMultisigScript(script)
|
||||||
) {
|
) {
|
||||||
@ -105,11 +111,11 @@ export function calcSegwitFeeGains(tx: Transaction) {
|
|||||||
|
|
||||||
// returned as percentage of the total tx weight
|
// returned as percentage of the total tx weight
|
||||||
return {
|
return {
|
||||||
realizedBech32Gains: realizedBech32Gains / (tx.weight + realizedBech32Gains), // percent of the pre-segwit tx size
|
realizedSegwitGains: realizedSegwitGains / (tx.weight + realizedSegwitGains), // percent of the pre-segwit tx size
|
||||||
potentialBech32Gains: potentialBech32Gains / tx.weight,
|
potentialSegwitGains: potentialSegwitGains / tx.weight,
|
||||||
potentialP2shGains: potentialP2shGains / tx.weight,
|
potentialP2shSegwitGains: potentialP2shSegwitGains / tx.weight,
|
||||||
potentialTaprootGains: potentialTaprootGains / tx.weight,
|
potentialTaprootGains: potentialTaprootGains / tx.weight,
|
||||||
realizedTaprootGains: realizedTaprootGains / tx.weight
|
realizedTaprootGains: realizedTaprootGains / (tx.weight + realizedTaprootGains)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,12 +194,12 @@ export function moveDec(num: number, n: number) {
|
|||||||
return neg + (int || '0') + (frac.length ? '.' + frac : '');
|
return neg + (int || '0') + (frac.length ? '.' + frac : '');
|
||||||
}
|
}
|
||||||
|
|
||||||
function zeros(n) {
|
function zeros(n: number) {
|
||||||
return new Array(n + 1).join('0');
|
return new Array(n + 1).join('0');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formats a number for display. Treats the number as a string to avoid rounding errors.
|
// Formats a number for display. Treats the number as a string to avoid rounding errors.
|
||||||
export const formatNumber = (s, precision = null) => {
|
export const formatNumber = (s: number | string, precision: number | null = null) => {
|
||||||
let [ whole, dec ] = s.toString().split('.');
|
let [ whole, dec ] = s.toString().split('.');
|
||||||
|
|
||||||
// divide numbers into groups of three separated with a thin space (U+202F, "NARROW NO-BREAK SPACE"),
|
// divide numbers into groups of three separated with a thin space (U+202F, "NARROW NO-BREAK SPACE"),
|
||||||
@ -219,27 +225,27 @@ const witnessSize = (vin: Vin) => vin.witness ? vin.witness.reduce((S, w) => S +
|
|||||||
const scriptSigSize = (vin: Vin) => vin.scriptsig ? vin.scriptsig.length / 2 : 0;
|
const scriptSigSize = (vin: Vin) => vin.scriptsig ? vin.scriptsig.length / 2 : 0;
|
||||||
|
|
||||||
// Power of ten wrapper
|
// Power of ten wrapper
|
||||||
export function selectPowerOfTen(val: number) {
|
export function selectPowerOfTen(val: number): { divider: number, unit: string } {
|
||||||
const powerOfTen = {
|
const powerOfTen = {
|
||||||
exa: Math.pow(10, 18),
|
exa: Math.pow(10, 18),
|
||||||
peta: Math.pow(10, 15),
|
peta: Math.pow(10, 15),
|
||||||
terra: Math.pow(10, 12),
|
tera: Math.pow(10, 12),
|
||||||
giga: Math.pow(10, 9),
|
giga: Math.pow(10, 9),
|
||||||
mega: Math.pow(10, 6),
|
mega: Math.pow(10, 6),
|
||||||
kilo: Math.pow(10, 3),
|
kilo: Math.pow(10, 3),
|
||||||
};
|
};
|
||||||
|
|
||||||
let selectedPowerOfTen;
|
let selectedPowerOfTen: { divider: number, unit: string };
|
||||||
if (val < powerOfTen.kilo) {
|
if (val < powerOfTen.kilo) {
|
||||||
selectedPowerOfTen = { divider: 1, unit: '' }; // no scaling
|
selectedPowerOfTen = { divider: 1, unit: '' }; // no scaling
|
||||||
} else if (val < powerOfTen.mega) {
|
} else if (val < powerOfTen.mega) {
|
||||||
selectedPowerOfTen = { divider: powerOfTen.kilo, unit: 'k' };
|
selectedPowerOfTen = { divider: powerOfTen.kilo, unit: 'k' };
|
||||||
} else if (val < powerOfTen.giga) {
|
} else if (val < powerOfTen.giga) {
|
||||||
selectedPowerOfTen = { divider: powerOfTen.mega, unit: 'M' };
|
selectedPowerOfTen = { divider: powerOfTen.mega, unit: 'M' };
|
||||||
} else if (val < powerOfTen.terra) {
|
} else if (val < powerOfTen.tera) {
|
||||||
selectedPowerOfTen = { divider: powerOfTen.giga, unit: 'G' };
|
selectedPowerOfTen = { divider: powerOfTen.giga, unit: 'G' };
|
||||||
} else if (val < powerOfTen.peta) {
|
} else if (val < powerOfTen.peta) {
|
||||||
selectedPowerOfTen = { divider: powerOfTen.terra, unit: 'T' };
|
selectedPowerOfTen = { divider: powerOfTen.tera, unit: 'T' };
|
||||||
} else if (val < powerOfTen.exa) {
|
} else if (val < powerOfTen.exa) {
|
||||||
selectedPowerOfTen = { divider: powerOfTen.peta, unit: 'P' };
|
selectedPowerOfTen = { divider: powerOfTen.peta, unit: 'P' };
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
<span *ngIf="segwitGains.realizedBech32Gains && !segwitGains.potentialBech32Gains; else segwitTwo" class="badge badge-success mr-1" i18n-ngbTooltip="ngbTooltip about segwit gains" ngbTooltip="This transaction saved {{ segwitGains.realizedBech32Gains * 100 | number: '1.0-0' }}% on fees by using native SegWit-Bech32" placement="bottom" i18n="tx-features.tag.segwit|SegWit">SegWit</span>
|
<span *ngIf="segwitGains.realizedSegwitGains && !segwitGains.potentialSegwitGains; else segwitTwo" class="badge badge-success mr-1" i18n-ngbTooltip="ngbTooltip about segwit gains" ngbTooltip="This transaction saved {{ segwitGains.realizedSegwitGains * 100 | number: '1.0-0' }}% on fees by using native SegWit" placement="bottom" i18n="tx-features.tag.segwit|SegWit">SegWit</span>
|
||||||
<ng-template #segwitTwo>
|
<ng-template #segwitTwo>
|
||||||
<span *ngIf="segwitGains.realizedBech32Gains && segwitGains.potentialBech32Gains; else potentialP2shGains" class="badge badge-warning mr-1" i18n-ngbTooltip="ngbTooltip about double segwit gains" ngbTooltip="This transaction saved {{ segwitGains.realizedBech32Gains * 100 | number: '1.0-0' }}% on fees by using SegWit and could save {{ segwitGains.potentialBech32Gains * 100 | number : '1.0-0' }}% more by fully upgrading to native SegWit-Bech32" placement="bottom" i18n="tx-features.tag.segwit|SegWit">SegWit</span>
|
<span *ngIf="segwitGains.realizedSegwitGains && segwitGains.potentialSegwitGains; else potentialP2shSegwitGains" class="badge badge-warning mr-1" i18n-ngbTooltip="ngbTooltip about double segwit gains" ngbTooltip="This transaction saved {{ segwitGains.realizedSegwitGains * 100 | number: '1.0-0' }}% on fees by using SegWit and could save {{ segwitGains.potentialSegwitGains * 100 | number : '1.0-0' }}% more by fully upgrading to native SegWit" placement="bottom" i18n="tx-features.tag.segwit|SegWit">SegWit</span>
|
||||||
<ng-template #potentialP2shGains>
|
<ng-template #potentialP2shSegwitGains>
|
||||||
<span *ngIf="segwitGains.potentialP2shGains" class="badge badge-danger mr-1" i18n-ngbTooltip="ngbTooltip about missed out gains" ngbTooltip="This transaction could save {{ segwitGains.potentialBech32Gains * 100 | number : '1.0-0' }}% on fees by upgrading to native SegWit-Bech32 or {{ segwitGains.potentialP2shGains * 100 | number: '1.0-0' }}% by upgrading to SegWit-P2SH" placement="bottom"><del i18n="tx-features.tag.segwit|SegWit">SegWit</del></span>
|
<span *ngIf="segwitGains.potentialP2shSegwitGains" class="badge badge-danger mr-1" i18n-ngbTooltip="ngbTooltip about missed out gains" ngbTooltip="This transaction could save {{ segwitGains.potentialSegwitGains * 100 | number : '1.0-0' }}% on fees by upgrading to native SegWit or {{ segwitGains.potentialP2shSegwitGains * 100 | number: '1.0-0' }}% by upgrading to SegWit-P2SH" placement="bottom"><del i18n="tx-features.tag.segwit|SegWit">SegWit</del></span>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<span *ngIf="segwitGains.realizedTaprootGains && !segwitGains.potentialTaprootGains; else notFullyTaproot" class="badge badge-success mr-1" i18n-ngbTooltip="Tooltip about privacy and fees saved with taproot" ngbTooltip="This transaction uses Taproot and the user's thereby increased privacy and saved at least {{ segwitGains.realizedTaprootGains * 100 | number: '1.0-0' }}% on fees" placement="bottom" i18n="tx-features.tag.taproot|Taproot">Taproot</span>
|
<span *ngIf="segwitGains.realizedTaprootGains && !segwitGains.potentialTaprootGains; else notFullyTaproot" class="badge badge-success mr-1" i18n-ngbTooltip="Tooltip about privacy and fees saved with taproot" ngbTooltip="This transaction uses Taproot and thereby increased the user's privacy and saved at least {{ segwitGains.realizedTaprootGains * 100 | number: '1.0-0' }}% on fees" placement="bottom" i18n="tx-features.tag.taproot|Taproot">Taproot</span>
|
||||||
<ng-template #notFullyTaproot>
|
<ng-template #notFullyTaproot>
|
||||||
<span *ngIf="segwitGains.realizedTaprootGains && segwitGains.potentialTaprootGains; else noTaproot" class="badge badge-warning mr-1" i18n-ngbTooltip="Tooltip about privacy and more fees that could be saved with more taproot" ngbTooltip="This transaction uses Taproot and thereby increased the user's privacy and already saved at least {{ segwitGains.realizedTaprootGains * 100 | number: '1.0-0' }}% on fees, but could save an additional {{ segwitGains.potentialTaprootGains * 100 | number: '1.0-0' }}% by fully using Taproot" placement="bottom" i18n="tx-features.tag.taproot|Taproot">Taproot</span>
|
<span *ngIf="segwitGains.realizedTaprootGains && segwitGains.potentialTaprootGains; else noTaproot" class="badge badge-warning mr-1" i18n-ngbTooltip="Tooltip about privacy and more fees that could be saved with more taproot" ngbTooltip="This transaction uses Taproot and thereby increased the user's privacy and already saved at least {{ segwitGains.realizedTaprootGains * 100 | number: '1.0-0' }}% on fees, but could save an additional {{ segwitGains.potentialTaprootGains * 100 | number: '1.0-0' }}% by fully using Taproot" placement="bottom" i18n="tx-features.tag.taproot|Taproot">Taproot</span>
|
||||||
<ng-template #noTaproot>
|
<ng-template #noTaproot>
|
||||||
|
@ -12,9 +12,9 @@ export class TxFeaturesComponent implements OnChanges {
|
|||||||
@Input() tx: Transaction;
|
@Input() tx: Transaction;
|
||||||
|
|
||||||
segwitGains = {
|
segwitGains = {
|
||||||
realizedBech32Gains: 0,
|
realizedSegwitGains: 0,
|
||||||
potentialBech32Gains: 0,
|
potentialSegwitGains: 0,
|
||||||
potentialP2shGains: 0,
|
potentialP2shSegwitGains: 0,
|
||||||
potentialTaprootGains: 0,
|
potentialTaprootGains: 0,
|
||||||
realizedTaprootGains: 0
|
realizedTaprootGains: 0
|
||||||
};
|
};
|
||||||
|
@ -43,11 +43,23 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr *ngIf="node.country && node.city && node.subdivision">
|
<tr *ngIf="node.country && node.city && node.subdivision">
|
||||||
<td i18n="location">Location</td>
|
<td i18n="location">Location</td>
|
||||||
<td>{{ node.city.en }}, {{ node.subdivision.en }}<br>{{ node.country.en }}</td>
|
<td>
|
||||||
|
<span>{{ node.city.en }}, {{ node.subdivision.en }}</span>
|
||||||
|
<br>
|
||||||
|
<a class="d-flex align-items-center" [routerLink]="['/lightning/nodes/country' | relativeUrl, node.iso_code]">
|
||||||
|
<span class="link">{{ node.country.en }}</span>
|
||||||
|
|
||||||
|
<span class="flag">{{ node.flag }}</span>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr *ngIf="node.country && !node.city">
|
<tr *ngIf="node.country && !node.city">
|
||||||
<td i18n="location">Location</td>
|
<td i18n="location">Location</td>
|
||||||
<td>{{ node.country.en }}</td>
|
<td>
|
||||||
|
<a [routerLink]="['/lightning/nodes/country' | relativeUrl, node.iso_code]">
|
||||||
|
{{ node.country.en }} {{ node.flag }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -77,7 +89,9 @@
|
|||||||
<tr *ngIf="node.country">
|
<tr *ngIf="node.country">
|
||||||
<td i18n="isp">ISP</td>
|
<td i18n="isp">ISP</td>
|
||||||
<td>
|
<td>
|
||||||
|
<a [routerLink]="['/lightning/nodes/isp' | relativeUrl, node.as_number]">
|
||||||
{{ node.as_organization }} [ASN {{node.as_number}}]
|
{{ node.as_organization }} [ASN {{node.as_number}}]
|
||||||
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -3,6 +3,7 @@ import { ActivatedRoute, ParamMap } from '@angular/router';
|
|||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { catchError, map, switchMap } from 'rxjs/operators';
|
import { catchError, map, switchMap } from 'rxjs/operators';
|
||||||
import { SeoService } from 'src/app/services/seo.service';
|
import { SeoService } from 'src/app/services/seo.service';
|
||||||
|
import { getFlagEmoji } from 'src/app/shared/graphs.utils';
|
||||||
import { LightningApiService } from '../lightning-api.service';
|
import { LightningApiService } from '../lightning-api.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -51,6 +52,7 @@ export class NodeComponent implements OnInit {
|
|||||||
} else if (socket.indexOf('onion') > -1) {
|
} else if (socket.indexOf('onion') > -1) {
|
||||||
label = 'Tor';
|
label = 'Tor';
|
||||||
}
|
}
|
||||||
|
node.flag = getFlagEmoji(node.iso_code);
|
||||||
socketsObject.push({
|
socketsObject.push({
|
||||||
label: label,
|
label: label,
|
||||||
socket: node.public_key + '@' + socket,
|
socket: node.public_key + '@' + socket,
|
||||||
|
@ -92,6 +92,9 @@ export function detectWebGL() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getFlagEmoji(countryCode) {
|
export function getFlagEmoji(countryCode) {
|
||||||
|
if (!countryCode) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
const codePoints = countryCode
|
const codePoints = countryCode
|
||||||
.toUpperCase()
|
.toUpperCase()
|
||||||
.split('')
|
.split('')
|
||||||
|
Loading…
Reference in New Issue
Block a user