Merge branch 'master' into flow-diagram-spent-connectors

This commit is contained in:
wiz
2022-11-22 13:42:33 +09:00
committed by GitHub
18 changed files with 180 additions and 37 deletions

View File

@@ -79,7 +79,7 @@ export const poolsColor = {
'binancepool': '#1E88E5',
'viabtc': '#039BE5',
'btccom': '#00897B',
'slushpool': '#00ACC1',
'braiinspool': '#00ACC1',
'sbicrypto': '#43A047',
'marapool': '#7CB342',
'luxor': '#C0CA33',

View File

@@ -188,7 +188,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
this.gl.viewport(0, 0, this.displayWidth, this.displayHeight);
}
if (this.scene) {
this.scene.resize({ width: this.displayWidth, height: this.displayHeight });
this.scene.resize({ width: this.displayWidth, height: this.displayHeight, animate: false });
this.start();
} else {
this.scene = new BlockScene({ width: this.displayWidth, height: this.displayHeight, resolution: this.resolution,

View File

@@ -29,7 +29,7 @@ export default class BlockScene {
this.init({ width, height, resolution, blockLimit, orientation, flip, vertexArray });
}
resize({ width = this.width, height = this.height }: { width?: number, height?: number}): void {
resize({ width = this.width, height = this.height, animate = true }: { width?: number, height?: number, animate: boolean }): void {
this.width = width;
this.height = height;
this.gridSize = this.width / this.gridWidth;
@@ -38,7 +38,7 @@ export default class BlockScene {
this.dirty = true;
if (this.initialised && this.scene) {
this.updateAll(performance.now(), 50);
this.updateAll(performance.now(), 50, 'left', animate);
}
}
@@ -212,7 +212,7 @@ export default class BlockScene {
this.vbytesPerUnit = blockLimit / Math.pow(resolution / 1.02, 2);
this.gridWidth = resolution;
this.gridHeight = resolution;
this.resize({ width, height });
this.resize({ width, height, animate: true });
this.layout = new BlockLayout({ width: this.gridWidth, height: this.gridHeight });
this.txs = {};
@@ -225,14 +225,14 @@ export default class BlockScene {
this.animateUntil = Math.max(this.animateUntil, tx.update(update));
}
private updateTx(tx: TxView, startTime: number, delay: number, direction: string = 'left'): void {
private updateTx(tx: TxView, startTime: number, delay: number, direction: string = 'left', animate: boolean = true): void {
if (tx.dirty || this.dirty) {
this.saveGridToScreenPosition(tx);
this.setTxOnScreen(tx, startTime, delay, direction);
this.setTxOnScreen(tx, startTime, delay, direction, animate);
}
}
private setTxOnScreen(tx: TxView, startTime: number, delay: number = 50, direction: string = 'left'): void {
private setTxOnScreen(tx: TxView, startTime: number, delay: number = 50, direction: string = 'left', animate: boolean = true): void {
if (!tx.initialised) {
const txColor = tx.getColor();
this.applyTxUpdate(tx, {
@@ -252,30 +252,42 @@ export default class BlockScene {
position: tx.screenPosition,
color: txColor
},
duration: 1000,
duration: animate ? 1000 : 1,
start: startTime,
delay,
delay: animate ? delay : 0,
});
} else {
this.applyTxUpdate(tx, {
display: {
position: tx.screenPosition
},
duration: 1000,
minDuration: 500,
duration: animate ? 1000 : 0,
minDuration: animate ? 500 : 0,
start: startTime,
delay,
adjust: true
delay: animate ? delay : 0,
adjust: animate
});
if (!animate) {
this.applyTxUpdate(tx, {
display: {
position: tx.screenPosition
},
duration: 0,
minDuration: 0,
start: startTime,
delay: 0,
adjust: false
});
}
}
}
private updateAll(startTime: number, delay: number = 50, direction: string = 'left'): void {
private updateAll(startTime: number, delay: number = 50, direction: string = 'left', animate: boolean = true): void {
this.scene.count = 0;
const ids = this.getTxList();
startTime = startTime || performance.now();
for (const id of ids) {
this.updateTx(this.txs[id], startTime, delay, direction);
this.updateTx(this.txs[id], startTime, delay, direction, animate);
}
this.dirty = false;
}

View File

@@ -117,8 +117,9 @@ export class TransactionPreviewComponent implements OnInit, OnDestroy {
}),
switchMap(() => {
let transactionObservable$: Observable<Transaction>;
if (history.state.data && history.state.data.fee !== -1) {
transactionObservable$ = of(history.state.data);
const cached = this.stateService.getTxFromCache(this.txId);
if (cached && cached.fee !== -1) {
transactionObservable$ = of(cached);
} else {
transactionObservable$ = this.electrsApiService
.getTransaction$(this.txId)

View File

@@ -3,7 +3,7 @@
<div class="title-block">
<div *ngIf="rbfTransaction" class="alert alert-mempool" role="alert">
<span i18n="transaction.rbf.replacement|RBF replacement">This transaction has been replaced by:</span>
<a class="alert-link" [routerLink]="['/tx/' | relativeUrl, rbfTransaction.txid]" [state]="{ data: rbfTransaction.size ? rbfTransaction : null }">
<a class="alert-link" [routerLink]="['/tx/' | relativeUrl, rbfTransaction.txid]">
<span class="d-inline d-lg-none">{{ rbfTransaction.txid | shortenString : 24 }}</span>
<span class="d-none d-lg-inline">{{ rbfTransaction.txid }}</span>
</a>

View File

@@ -183,8 +183,9 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
}),
switchMap(() => {
let transactionObservable$: Observable<Transaction>;
if (history.state.data && history.state.data.fee !== -1) {
transactionObservable$ = of(history.state.data);
const cached = this.stateService.getTxFromCache(this.txId);
if (cached && cached.fee !== -1) {
transactionObservable$ = of(cached);
} else {
transactionObservable$ = this.electrsApiService
.getTransaction$(this.txId)
@@ -279,6 +280,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
this.waitingForTransaction = false;
}
this.rbfTransaction = rbfTransaction;
this.stateService.setTxCache([this.rbfTransaction]);
});
this.queryParamsSubscription = this.route.queryParams.subscribe((params) => {

View File

@@ -1,6 +1,6 @@
<ng-container *ngFor="let tx of transactions; let i = index; trackBy: trackByFn">
<div *ngIf="!transactionPage" class="header-bg box tx-page-container">
<a class="float-left" [routerLink]="['/tx/' | relativeUrl, tx.txid]" [state]="{ data: tx }">
<a class="float-left" [routerLink]="['/tx/' | relativeUrl, tx.txid]">
<span style="float: left;" class="d-block d-md-none">{{ tx.txid | shortenString : 16 }}</span>
<span style="float: left;" class="d-none d-md-block">{{ tx.txid }}</span>
</a>

View File

@@ -119,7 +119,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
}
this.transactionsLength = this.transactions.length;
this.stateService.setTxCache(this.transactions);
this.transactions.forEach((tx) => {
tx['@voutLimit'] = true;

View File

@@ -9,6 +9,11 @@
<div class="doc-content">
<div id="disclaimer">
<table><tr><td><svg viewBox="0 0 304 304" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd" style="fill:#ffc107;fill-opacity:1"><path d="M135.3 34.474c-15.62 27.306-54.206 95.63-85.21 150.534L9.075 257.583C5.382 264.08 6.76 269.217 7.908 271.7c2.326 5.028 7.29 7.537 11.155 8.215l.78.133 264.698.006-.554-.02c4.152.255 9.664-1.24 12.677-6.194 1.926-3.18 3.31-8.589-1.073-16.278L213.637 114.37l-45.351-79.205c-5.681-9.932-12.272-12.022-16.8-12.022-4.42 0-10.818 1.964-16.181 11.331h-.006zm-69.072 159.94c30.997-54.885 69.563-123.184 85.16-150.446l.186-.297c.2.303.393.582.618.981l45.363 79.22s72.377 126.47 78.569 137.283l-247.618-.007 37.719-66.734" style="fill:#ffc107;fill-opacity:1"/><path d="M152.597 247.445c8.02 0 14.518-6.728 14.518-15.025 0-8.29-6.499-15.018-14.518-15.018-8.031 0-14.529 6.728-14.529 15.018 0 8.297 6.498 15.025 14.53 15.025m-.001-147.18c11.586 0 22.23 10.958 20.977 21.7l-9.922 75.564c-.966 6.601-4.95 11.433-11.055 11.433s-10.102-4.832-11.056-11.433l-9.927-75.564c-1.26-10.742 9.39-21.7 20.983-21.7" style="fill:#ffc107;fill-opacity:1"/></g></svg></td><td><p><b>mempool.space merely provides data about the Bitcoin network.</b> It cannot help you with retrieving funds, confirming your transaction quicker, etc.</p><p>For any such requests, you need to get in touch with the entity that helped make the transaction (wallet software, exchange company, etc).</p></td></tr></table>
</div>
<div class="doc-item-container" *ngFor="let item of faq">
<h3 *ngIf="item.type === 'category'">{{ item.title }}</h3>
<div *ngIf="item.type !== 'category'" class="endpoint-container" id="{{ item.fragment }}">

View File

@@ -219,6 +219,22 @@ h3 {
display: none;
}
#disclaimer {
background-color: #1d1f31;
padding: 24px;
margin: 24px 0;
}
#disclaimer svg {
width: 50px;
height: auto;
margin-right: 32px;
}
#disclaimer p:last-child {
margin-bottom: 0;
}
@media (max-width: 992px) {
h3 {

View File

@@ -30,7 +30,7 @@
<pre><code [innerText]="wrapEsModule(code)"></code></pre>
</ng-template>
</li>
<li ngbNavItem *ngIf="showCodeExample[network] && network !== 'liquid' && network !== 'liquidtestnet'" role="presentation">
<li ngbNavItem *ngIf="code.codeTemplate.python && network !== 'liquid' && network !== 'liquidtestnet'" role="presentation">
<a ngbNavLink (click)="adjustContainerHeight( $event )" role="tab">Python</a>
<ng-template ngbNavContent>
<div class="subtitle"><ng-container i18n="API Docs code example">Code Example</ng-container> <app-clipboard [text]="wrapEsModule(code)"></app-clipboard></div>

View File

@@ -52,6 +52,10 @@
<span i18n="unknown">Unknown</span>
</td>
</tr>
<tr *ngIf="(avgChannelDistance$ | async) as avgDistance;">
<td i18n="lightning.avg-distance" class="text-truncate">Avg channel distance</td>
<td>{{ avgDistance | number : '1.0-0' }} <span class="symbol">km</span> <span class="separator">/</span> {{ kmToMiles(avgDistance) | number : '1.0-0' }} <span class="symbol">mi</span></td>
</tr>
</tbody>
</table>
</div>

View File

@@ -101,3 +101,7 @@ app-fiat {
font-family: "Courier New", Courier, monospace;
}
}
.separator {
margin: 0 1em;
}

View File

@@ -3,9 +3,11 @@ import { ActivatedRoute, ParamMap } from '@angular/router';
import { Observable } from 'rxjs';
import { catchError, map, switchMap, tap } from 'rxjs/operators';
import { SeoService } from '../../services/seo.service';
import { ApiService } from '../../services/api.service';
import { LightningApiService } from '../lightning-api.service';
import { GeolocationData } from '../../shared/components/geolocation/geolocation.component';
import { ILiquidityAd, parseLiquidityAdHex } from './liquidity-ad';
import { haversineDistance, kmToMiles } from 'src/app/shared/common.utils';
interface CustomRecord {
type: string;
@@ -34,8 +36,12 @@ export class NodeComponent implements OnInit {
showDetails = false;
liquidityAd: ILiquidityAd;
tlvRecords: CustomRecord[];
avgChannelDistance$: Observable<number | null>;
kmToMiles = kmToMiles;
constructor(
private apiService: ApiService,
private lightningApiService: LightningApiService,
private activatedRoute: ActivatedRoute,
private seoService: SeoService,
@@ -119,6 +125,26 @@ export class NodeComponent implements OnInit {
}];
})
);
this.avgChannelDistance$ = this.activatedRoute.paramMap
.pipe(
switchMap((params: ParamMap) => {
return this.apiService.getChannelsGeo$(params.get('public_key'), 'nodepage');
}),
map((channelsGeo) => {
if (channelsGeo?.length) {
const totalDistance = channelsGeo.reduce((sum, chan) => {
return sum + haversineDistance(chan[3], chan[2], chan[7], chan[6]);
}, 0);
return totalDistance / channelsGeo.length;
} else {
return null;
}
}),
catchError(() => {
return null;
})
) as Observable<number | null>;
}
toggleShowDetails(): void {

View File

@@ -112,6 +112,8 @@ export class StateService {
timeLtr: BehaviorSubject<boolean>;
hideFlow: BehaviorSubject<boolean>;
txCache: { [txid: string]: Transaction } = {};
constructor(
@Inject(PLATFORM_ID) private platformId: any,
@Inject(LOCALE_ID) private locale: string,
@@ -265,4 +267,19 @@ export class StateService {
isLiquid() {
return this.network === 'liquid' || this.network === 'liquidtestnet';
}
setTxCache(transactions) {
this.txCache = {};
transactions.forEach(tx => {
this.txCache[tx.txid] = tx;
});
}
getTxFromCache(txid) {
if (this.txCache && this.txCache[txid]) {
return this.txCache[txid];
} else {
return null;
}
}
}

View File

@@ -118,3 +118,21 @@ export function convertRegion(input, to: 'name' | 'abbreviated'): string {
}
}
}
export function haversineDistance(lat1: number, lon1: number, lat2: number, lon2: number): number {
const rlat1 = lat1 * Math.PI / 180;
const rlon1 = lon1 * Math.PI / 180;
const rlat2 = lat2 * Math.PI / 180;
const rlon2 = lon2 * Math.PI / 180;
const dlat = Math.sin((rlat2 - rlat1) / 2);
const dlon = Math.sin((rlon2 - rlon1) / 2);
const a = Math.min(1, Math.max(0, (dlat * dlat) + (Math.cos(rlat1) * Math.cos(rlat2) * dlon * dlon)));
const d = 2 * 6371 * Math.asin(Math.sqrt(a));
return d;
}
export function kmToMiles(km: number): number {
return km * 0.62137119;
}