diff --git a/frontend/package.json b/frontend/package.json index 9204cd07e8..50918c207f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "frontend", - "version": "0.8.14", + "version": "0.8.15", "scripts": { "install:deps": "npm install", "start": "npm install && ng serve --configuration local --open", diff --git a/frontend/src/app/app.service.ts b/frontend/src/app/app.service.ts index bd7eb01448..485ca5cc7c 100644 --- a/frontend/src/app/app.service.ts +++ b/frontend/src/app/app.service.ts @@ -27,9 +27,9 @@ export class AppService { } getActiveNodeDetails(): Observable { - return this.rust.get('/status') + return this.rust.get('/status') .pipe( - map((data: NodeDetails) => ({ + map((data: NodeDetailsResponse) => ({ status: this.getStatus(data), blockHeight: data.transition_frontier.best_tip.height, blockTime: data.transition_frontier.sync.time, @@ -39,34 +39,34 @@ export class AppService { snarks: data.snark_pool.snarks, transactions: data.transaction_pool.transactions, } as AppNodeDetails)), - catchError((err) => { - return of({ - status: AppNodeStatus.OFFLINE, - blockHeight: null, - blockTime: null, - peers: 0, - download: 0, - upload: 0, - transactions: 0, - snarks: 0, - } as AppNodeDetails); - }), + catchError(() => of({ + status: AppNodeStatus.OFFLINE, + blockHeight: null, + blockTime: null, + peers: 0, + download: 0, + upload: 0, + transactions: 0, + snarks: 0, + } as AppNodeDetails)), ); } - private getStatus(data: NodeDetails): AppNodeStatus { + private getStatus(data: NodeDetailsResponse): AppNodeStatus { + if (data.transition_frontier.sync.status === 'Bootstrap') { + return AppNodeStatus.BOOTSTRAP; + } + if (data.transition_frontier.sync.status === 'Catchup') { + return AppNodeStatus.CATCHUP; + } if (data.transition_frontier.sync.status === 'Synced') { return AppNodeStatus.SYNCED; - } else { - if (data.transition_frontier.best_tip === null) { - return AppNodeStatus.BOOTSTRAP; - } - return AppNodeStatus.CATCHUP; } + return AppNodeStatus.PENDING; } } -interface NodeDetails { +export interface NodeDetailsResponse { transition_frontier: TransitionFrontier; transaction_pool: { transactions: number }; peers: Peer[]; @@ -88,6 +88,7 @@ interface Sync { time: number; status: string; target: any; + phase: 'Bootstrap' | 'Catchup' | 'Synced'; } interface Peer { diff --git a/frontend/src/app/core/services/rust.service.ts b/frontend/src/app/core/services/rust.service.ts index 26c8e8d01c..3379eda818 100644 --- a/frontend/src/app/core/services/rust.service.ts +++ b/frontend/src/app/core/services/rust.service.ts @@ -57,7 +57,7 @@ export class RustService { case '/stats/block_producer': return this.webNodeService.blockProducerStats$; default: - throw new Error('Unknown path for web node'); + throw new Error(`Web node doesn't support "${path}" path!`); } } } diff --git a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets-toolbar/benchmarks-wallets-toolbar.component.html b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets-toolbar/benchmarks-wallets-toolbar.component.html index c49b1ae9e8..3148af6c57 100644 --- a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets-toolbar/benchmarks-wallets-toolbar.component.html +++ b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets-toolbar/benchmarks-wallets-toolbar.component.html @@ -14,10 +14,16 @@
diff --git a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.reducer.ts b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.reducer.ts index 1fb3106c7b..94f68b76ab 100644 --- a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.reducer.ts +++ b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.reducer.ts @@ -33,7 +33,7 @@ const initialState: BenchmarksWalletsState = { sentTxCount: 0, randomWallet: true, activeWallet: undefined, - sendingFee: 1, + sendingFee: 0.001, }; export function reducer(state: BenchmarksWalletsState = initialState, action: BenchmarksWalletsActions): BenchmarksWalletsState { @@ -99,9 +99,9 @@ export function reducer(state: BenchmarksWalletsState = initialState, action: Be from: wallet.publicKey, nonce, to: getRandomReceiver(wallet, state.wallets), - // to: 'B62qp6QqfMrDGULkuCTMhLYrG4iTxnjnyS3pv8bFppRsz488HCxExEY', // Teo's ledger address + // to: 'B62qp6QqfMrDGULkuCTMhLYrG4iTxnjnyS3pv8bFppRsz488HCxExEY', // Teo's work Ledger address fee: (state.sendingFee * ONE_BILLION).toString(), - amount: (2 * ONE_BILLION).toString(), + amount: (1 * ONE_BILLION).toString(), memo, validUntil: '4294967295', }; @@ -123,7 +123,7 @@ export function reducer(state: BenchmarksWalletsState = initialState, action: Be nonce: nonce.toString(), to: state.wallets[i].publicKey, fee: (state.sendingFee * ONE_BILLION).toString(), - amount: (2 * ONE_BILLION).toString(), + amount: (1 * ONE_BILLION).toString(), memo, validUntil: '4294967295', }; diff --git a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.service.ts b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.service.ts index 8d5997b1c6..5c3e7c8401 100644 --- a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.service.ts +++ b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.service.ts @@ -13,6 +13,10 @@ import { getTimeFromMemo, removeUnicodeEscapes } from '@shared/helpers/transacti import { any, ONE_BILLION } from '@openmina/shared'; export const WALLETS: { privateKey: string, publicKey: string }[] = [ + { + privateKey: 'EKEQGWy4TjbVeqKjbe7TW81DKQM34min5FNmXpKArHKLyGVd3KSP', + publicKey: 'B62qpD75xH5R19wxZG2uz8whNsHPTioVoYcPV3zfjjSbzTmaHQHKKEV', + }, { privateKey: 'EKETKywEr7ktbzqj8D2aj4yYZVMyj33sHuWLQydbzt1M3sGnAbTh', publicKey: 'B62qnLjgW4LAnrxkcdLc7Snb49qx6aP5qsmPsp6ueZN4XPMC621cqGc', @@ -4009,10 +4013,10 @@ export const WALLETS: { privateKey: string, publicKey: string }[] = [ privateKey: 'EKEA8wHHpnBCzzNvCJSPqoaF66V9cQcpd7xNN9kQxs36PV293pcU', publicKey: 'B62qrZG1qRV82D2CJa9FJW5BYMyC7AbL1J5aKVEgi6VMmBNcHVreozY', }, - { - privateKey: 'EKEeNntJDZ7whPrxjNKPTj2QisoKdzWzJ59s2KmxaLHJWJhPKKxY', - publicKey: 'B62qruoEM1ijZPXkkLubNKRn8DQHbdfTG2BP8ut4kE4EqxT7EmnMGRA', - }, + // { + // privateKey: 'EKEeNntJDZ7whPrxjNKPTj2QisoKdzWzJ59s2KmxaLHJWJhPKKxY', + // publicKey: 'B62qruoEM1ijZPXkkLubNKRn8DQHbdfTG2BP8ut4kE4EqxT7EmnMGRA', + // }, ]; @Injectable({ @@ -4037,9 +4041,15 @@ export class BenchmarksWalletsService { nonce: wallet.nonce, }))), // TODO: This is a backend issue, must delete this map when we have all 1000 accounts in the backend - map(wall => { + map(wallets => { return [ - ...wall.filter(w => WALLETS.map(w => w.publicKey).includes(w.publicKey)), + ...wallets.filter(w => WALLETS.map(w => w.publicKey).includes(w.publicKey)), + ...WALLETS.filter(w => !wallets.some(w1 => w1.publicKey === w.publicKey)).map(wallet => ({ + privateKey: wallet.privateKey, + publicKey: wallet.publicKey, + minaTokens: 0, + nonce: 0, + })), ]; }), ); diff --git a/frontend/src/app/features/block-production/won-slots/block-production-won-slots.service.ts b/frontend/src/app/features/block-production/won-slots/block-production-won-slots.service.ts index ad03c070ad..fb6e7bfbab 100644 --- a/frontend/src/app/features/block-production/won-slots/block-production-won-slots.service.ts +++ b/frontend/src/app/features/block-production/won-slots/block-production-won-slots.service.ts @@ -43,9 +43,9 @@ export class BlockProductionWonSlotsService { height: attempt.block?.height, hash: attempt.block?.hash, transactionsTotal: nanOrElse(attempt.block?.transactions.payments + attempt.block?.transactions.delegations + attempt.block?.transactions.zkapps, 0), + zkapps: nanOrElse(attempt.block?.transactions.zkapps, 0), payments: nanOrElse(attempt.block?.transactions.payments, 0), delegations: nanOrElse(attempt.block?.transactions.delegations, 0), - zkapps: nanOrElse(attempt.block?.transactions.zkapps, 0), completedWorksCount: nanOrElse(attempt.block?.completed_works_count, 0), snarkFees: attempt.block ? attempt.block.snark_fees / ONE_BILLION : undefined, coinbaseRewards: attempt.block ? attempt.block.coinbase / ONE_BILLION : undefined, diff --git a/frontend/src/app/features/dashboard/dashboard.service.ts b/frontend/src/app/features/dashboard/dashboard.service.ts index 68a742cba2..9b27c7ffc3 100644 --- a/frontend/src/app/features/dashboard/dashboard.service.ts +++ b/frontend/src/app/features/dashboard/dashboard.service.ts @@ -40,7 +40,7 @@ export class DashboardService { getTips({ url, name }: { url: string, name: string }): Observable { return this.rust.get('/stats/sync?limit=1').pipe( - map((response: NodesOverviewNode[]) => this.nodesOverviewService.mapNodeTipsResponse(response, true, { + map((response: NodesOverviewNode[]) => this.nodesOverviewService.mapNodeTipsResponse([response, undefined], { name, url, })), diff --git a/frontend/src/app/features/mempool/filters/mempool-filters.component.html b/frontend/src/app/features/mempool/filters/mempool-filters.component.html index 7d4604875d..d662b24efb 100644 --- a/frontend/src/app/features/mempool/filters/mempool-filters.component.html +++ b/frontend/src/app/features/mempool/filters/mempool-filters.component.html @@ -22,7 +22,7 @@
{{ zkApps }} ZKApp command @@ -31,7 +31,7 @@
{{ payments }} Payment diff --git a/frontend/src/app/features/mempool/table/mempool-table.component.html b/frontend/src/app/features/mempool/table/mempool-table.component.html index f85fd86081..fee090f2b3 100644 --- a/frontend/src/app/features/mempool/table/mempool-table.component.html +++ b/frontend/src/app/features/mempool/table/mempool-table.component.html @@ -1,7 +1,10 @@ - {{ row.kind }} + + {{ row.kind }} + {{ row.txHash | truncateMid }} {{ row.sender | truncateMid }} {{ row.fee }} diff --git a/frontend/src/app/features/mempool/table/mempool-table.component.scss b/frontend/src/app/features/mempool/table/mempool-table.component.scss index 55dc3d615e..587d6cd5ce 100644 --- a/frontend/src/app/features/mempool/table/mempool-table.component.scss +++ b/frontend/src/app/features/mempool/table/mempool-table.component.scss @@ -23,3 +23,18 @@ background-color: $special-selected-alt-2-container; color: $special-selected-alt-2-primary; } + +.status { + padding: 3px 5px; + border-radius: 4px; + + &.ZKApp { + background-color: $special-selected-alt-1-container; + color: $special-selected-alt-1-primary; + } + + &.Payment { + background-color: $special-selected-alt-3-container; + color: $special-selected-alt-3-primary; + } +} diff --git a/frontend/src/app/features/nodes/bootstrap/nodes-bootstrap-table/nodes-bootstrap-table.component.ts b/frontend/src/app/features/nodes/bootstrap/nodes-bootstrap-table/nodes-bootstrap-table.component.ts index bdb1d147b9..f9e560342d 100644 --- a/frontend/src/app/features/nodes/bootstrap/nodes-bootstrap-table/nodes-bootstrap-table.component.ts +++ b/frontend/src/app/features/nodes/bootstrap/nodes-bootstrap-table/nodes-bootstrap-table.component.ts @@ -5,13 +5,13 @@ import { MergedRoute, SEC_CONFIG_GRAY_PALETTE, SecDurationConfig, - TableColumnList + TableColumnList, } from '@openmina/shared'; import { Router } from '@angular/router'; import { NodesBootstrapSetActiveBlock, NodesBootstrapSortNodes, - NodesBootstrapToggleSidePanel + NodesBootstrapToggleSidePanel, } from '@nodes/bootstrap/nodes-bootstrap.actions'; import { selectNodesBootstrapActiveNode, @@ -38,24 +38,24 @@ export class NodesBootstrapTableComponent extends MinaTableRustWrapper = [ { name: '#', sort: 'index' }, - { name: 'global slot', sort: 'globalSlot', tooltip: 'The block’s slot irrespective of Mina epochs.' }, - { name: 'height', tooltip: 'The block height.' }, - { name: 'best tip', sort: 'bestTip', tooltip: 'Best tip to which node tried to synchronize.' }, - { name: 'amount', sort: 'fetchedBlocks', tooltip: 'Total amount of fetched blocks.' }, - { name: 'min', sort: 'fetchedBlocksMin', tooltip: 'Minimum time it took to fetch a block.' }, - { name: 'max', sort: 'fetchedBlocksMax', tooltip: 'Maximum time it took to fetch a block.' }, - { name: 'avg', sort: 'fetchedBlocksAvg', tooltip: 'Average time it took to fetch a block.' }, - { name: 'amount', sort: 'appliedBlocks', tooltip: 'Total amount of applied blocks.' }, - { name: 'min', sort: 'appliedBlocksMin', tooltip: 'Minimum time it took to apply a block.' }, - { name: 'max', sort: 'appliedBlocksMax', tooltip: 'Maximum time it took to apply a block.' }, - { name: 'avg', sort: 'appliedBlocksAvg', tooltip: 'Average time it took to apply a block.' }, + { name: 'global slot', sort: 'globalSlot' }, + { name: 'height' }, + { name: 'best tip', sort: 'bestTip' }, + { name: 'amount', sort: 'fetchedBlocks' }, + { name: 'min', sort: 'fetchedBlocksMin' }, + { name: 'max', sort: 'fetchedBlocksMax' }, + { name: 'avg', sort: 'fetchedBlocksAvg' }, + { name: 'amount', sort: 'appliedBlocks' }, + { name: 'min', sort: 'appliedBlocksMin' }, + { name: 'max', sort: 'appliedBlocksMax' }, + { name: 'avg', sort: 'appliedBlocksAvg' }, ]; private indexFromRoute: number; diff --git a/frontend/src/app/features/nodes/overview/nodes-overview.effects.ts b/frontend/src/app/features/nodes/overview/nodes-overview.effects.ts index dfe9d24047..d1574c0e1b 100644 --- a/frontend/src/app/features/nodes/overview/nodes-overview.effects.ts +++ b/frontend/src/app/features/nodes/overview/nodes-overview.effects.ts @@ -57,10 +57,7 @@ export class NodesOverviewEffects extends MinaRustBaseEffect(), mergeMap(({ action }) => - this.nodesOverviewService.getNodeTips({ - url: action.payload.url, - name: action.payload.name, - }, '?limit=1', true), + this.nodesOverviewService.getNodeTips({ url: action.payload.url, name: action.payload.name }, '?limit=1'), ), map((nodeTips: NodesOverviewNode[]) => ({ type: NODES_OVERVIEW_GET_NODE_STATUS_SUCCESS, diff --git a/frontend/src/app/features/nodes/overview/nodes-overview.service.ts b/frontend/src/app/features/nodes/overview/nodes-overview.service.ts index 2f8d19c9a7..46934b6543 100644 --- a/frontend/src/app/features/nodes/overview/nodes-overview.service.ts +++ b/frontend/src/app/features/nodes/overview/nodes-overview.service.ts @@ -12,40 +12,28 @@ import { NodesOverviewLedgerEpochStep, NodesOverviewLedgerStepState, } from '@shared/types/nodes/dashboard/nodes-overview-ledger.type'; -import { MinaNode } from '@shared/types/core/environment/mina-env.type'; import { NodesOverviewResync } from '@shared/types/nodes/dashboard/nodes-overview-resync.type'; -import { AppNodeStatus } from '@shared/types/app/app-node-details.type'; +import { NodeDetailsResponse } from '@app/app.service'; @Injectable({ providedIn: 'root', }) export class NodesOverviewService { - constructor(private http: HttpClient) { - } - - getNodes(nodes: MinaNode[]): Observable { - return forkJoin( - nodes.map((node: MinaNode) => { - return this.getNodeTips({ url: node.url, name: node.name }, '?limit=1'); - }), - ).pipe( - map((nodes: NodesOverviewNode[][]) => nodes.map(n => n[0])), - ); - } + constructor(private http: HttpClient) {} - getNodeTips(nodeParam: { - url: string, - name: string - }, qp: string = '', onlyOne: boolean = false): Observable { - return this.http.get(nodeParam.url + '/stats/sync' + qp) + getNodeTips(nodeParam: { url: string, name: string }, qp: string = ''): Observable { + return forkJoin([ + this.http.get(nodeParam.url + '/stats/sync' + qp), + this.http.get(nodeParam.url + '/status' + qp), + ]) .pipe( - map((response: any[]) => this.mapNodeTipsResponse(response, onlyOne, nodeParam)), + map((response: [any, NodeDetailsResponse]) => this.mapNodeTipsResponse(response, nodeParam)), catchError(err => this.mapNodeTipsErrorResponse(nodeParam)), ); } - public mapNodeTipsErrorResponse(nodeParam: { url: string; name: string }) { + public mapNodeTipsErrorResponse(nodeParam: { url: string; name: string }): Observable { return of([{ name: nodeParam.name, kind: NodesOverviewNodeKindType.OFFLINE, @@ -65,34 +53,34 @@ export class NodesOverviewService { }]); } - public mapNodeTipsResponse(response: any[], onlyOne: boolean, nodeParam: { url: string; name: string }) { - if (response.length === 0) { + public mapNodeTipsResponse([syncTips, nodeDetails]: [any, NodeDetailsResponse | undefined], nodeParam: { + url: string; + name: string + }): NodesOverviewNode[] { + if (syncTips.length === 0) { throw new Error('Empty response'); } - return response - .slice(0, onlyOne ? 1 : response.length) + return syncTips .map((node: any) => { - const blocks = node.blocks.map((block: any) => { - return { - globalSlot: block.global_slot, - height: block.height, - hash: block.hash, - predHash: block.pred_hash, - status: block.status, - fetchStart: block.fetch_start, - fetchEnd: block.fetch_end, - applyStart: block.apply_start, - applyEnd: block.apply_end, - fetchDuration: this.getDuration(block.fetch_start, block.fetch_end), - applyDuration: this.getDuration(block.apply_start, block.apply_end), - } as NodesOverviewBlock; - }); + const blocks = node.blocks.map((block: any) => ({ + globalSlot: block.global_slot, + height: block.height, + hash: block.hash, + predHash: block.pred_hash, + status: block.status, + fetchStart: block.fetch_start, + fetchEnd: block.fetch_end, + applyStart: block.apply_start, + applyEnd: block.apply_end, + fetchDuration: this.getDuration(block.fetch_start, block.fetch_end), + applyDuration: this.getDuration(block.apply_start, block.apply_end), + } as NodesOverviewBlock)); if (blocks.length) { blocks[0].isBestTip = true; } return { name: nodeParam.name, - kind: hasValue(node.synced) ? NodesOverviewNodeKindType.SYNCED : node.kind, + kind: nodeDetails?.transition_frontier.sync.phase, bestTipReceived: toReadableDate(node.best_tip_received / ONE_MILLION), bestTipReceivedTimestamp: node.best_tip_received / ONE_MILLION, bestTip: node.blocks[0]?.hash,