diff --git a/frontend/src/app/app.routing.ts b/frontend/src/app/app.routing.ts index 7918f7fd26..fe601d58a6 100644 --- a/frontend/src/app/app.routing.ts +++ b/frontend/src/app/app.routing.ts @@ -1,6 +1,6 @@ import { NgModule } from '@angular/core'; -import { PreloadAllModules, RouterModule, Routes } from '@angular/router'; -import { getFirstFeature } from '@shared/constants/config'; +import { NoPreloading, PreloadAllModules, RouterModule, Routes } from '@angular/router'; +import { CONFIG, getFirstFeature } from '@shared/constants/config'; const APP_TITLE: string = 'Open Mina'; @@ -79,7 +79,7 @@ const routes: Routes = [ imports: [ RouterModule.forRoot(routes, { // enableTracing: true, - preloadingStrategy: PreloadAllModules, + preloadingStrategy: CONFIG.configs.some(c => c.isWebNode) ? NoPreloading : PreloadAllModules, onSameUrlNavigation: 'ignore', initialNavigation: 'enabledNonBlocking', }), diff --git a/frontend/src/app/core/services/rust.service.ts b/frontend/src/app/core/services/rust.service.ts index 3379eda818..6f428c7436 100644 --- a/frontend/src/app/core/services/rust.service.ts +++ b/frontend/src/app/core/services/rust.service.ts @@ -37,6 +37,12 @@ export class RustService { } post(path: string, body: B): Observable { + if (this.node.isWebNode) { + return this.postToWebNode(path, body).pipe(map((response: any) => { + // console.log(path, response); + return response; + })); + } return this.http.post(this.URL + path, body); } @@ -56,6 +62,21 @@ export class RustService { return this.webNodeService.sync$; case '/stats/block_producer': return this.webNodeService.blockProducerStats$; + case '/transaction-pool': + return this.webNodeService.transactionPool$; + case '/accounts': + return this.webNodeService.accounts$; + case '/best-chain-user-commands': + return this.webNodeService.bestChainUserCommands$; + default: + throw new Error(`Web node doesn't support "${path}" path!`); + } + } + + private postToWebNode(path: string, body: B): Observable { + switch (path) { + case '/send-payment': + return this.webNodeService.sendPayment$(body); default: throw new Error(`Web node doesn't support "${path}" path!`); } diff --git a/frontend/src/app/core/services/web-node.service.ts b/frontend/src/app/core/services/web-node.service.ts index e595e5d00a..ff310e16fc 100644 --- a/frontend/src/app/core/services/web-node.service.ts +++ b/frontend/src/app/core/services/web-node.service.ts @@ -1,8 +1,8 @@ import { Injectable } from '@angular/core'; -import { BehaviorSubject, filter, from, fromEvent, map, Observable, of, switchMap, tap } from 'rxjs'; +import { BehaviorSubject, filter, from, fromEvent, map, merge, Observable, of, switchMap, tap } from 'rxjs'; import base from 'base-x'; import { any, log } from '@openmina/shared'; -import { CONFIG } from '@shared/constants/config'; +import { HttpClient } from '@angular/common/http'; @Injectable({ providedIn: 'root', @@ -11,9 +11,10 @@ export class WebNodeService { private readonly backendSubject$: BehaviorSubject = new BehaviorSubject(null); private backend: any; + private webNodeKeyPair: { publicKey: string, privateKey: string }; webNodeState: string = 'notLoaded'; - constructor() { + constructor(private http: HttpClient) { const basex = base('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'); any(window)['bs58btc'] = { encode: (buffer: Uint8Array | number[]) => 'z' + basex.encode(buffer), @@ -22,19 +23,25 @@ export class WebNodeService { } loadWasm$(): Observable { - if ((window as any).webnode) { - return of(void 0); - } - return fromEvent(window, 'webNodeLoaded').pipe(map(() => void 0)); + console.log('---LOADING WASM'); + return merge( + of(any(window).webnode).pipe(filter(Boolean)), + fromEvent(window, 'webNodeLoaded'), + ).pipe( + switchMap(() => this.http.get<{ publicKey: string, privateKey: string }>('assets/webnode/web-node-secrets.json')), + tap(data => this.webNodeKeyPair = data), + map(() => void 0), + ); } startWasm$(): Observable { - return of((window as any).webnode) + console.log('---STARTING WASM'); + return of(any(window).webnode) .pipe( switchMap((wasm: any) => from(wasm.default('assets/webnode/pkg/openmina_node_web_bg.wasm')).pipe(map(() => wasm))), switchMap((wasm) => { console.log(wasm); - return from(wasm.run(CONFIG.webNodeKey)); + return from(wasm.run(this.webNodeKeyPair.privateKey)); }), tap((jsHandle: any) => { this.backend = jsHandle; @@ -47,10 +54,15 @@ export class WebNodeService { ); } + get webNodeKeys(): { publicKey: string, privateKey: string } { + return this.webNodeKeyPair; + } + get status$(): Observable { return this.backendSubject$.asObservable().pipe( filter(Boolean), switchMap(handle => from((handle as any).status())), + log(), ); } @@ -81,4 +93,40 @@ export class WebNodeService { switchMap(handle => from((handle as any).stats().sync())), ); } + + get accounts$(): Observable { + return this.backendSubject$.asObservable().pipe( + filter(Boolean), + switchMap(handle => from((handle as any).ledger().latest().accounts().all())), + ); + } + + get bestChainUserCommands$(): Observable { + console.log('---GETTING BEST CHAIN USER COMMANDS'); + return this.backendSubject$.asObservable().pipe( + filter(Boolean), + switchMap(handle => from((handle as any).transition_frontier().best_chain().user_commands())), + tap((r) => { + console.log('response from GETTING BEST CHAIN USER COMMANDS', r); + }), + ); + } + + sendPayment$(payment: any): Observable { + return this.backendSubject$.asObservable().pipe( + filter(Boolean), + switchMap(handle => from((handle as any).transaction_pool().inject().payment(payment))), + ); + } + + get transactionPool$(): Observable { + console.log('---GETTING TRANSACTION POOL'); + return this.backendSubject$.asObservable().pipe( + filter(Boolean), + switchMap(handle => from((handle as any).transaction_pool().get())), + tap((r) => { + console.log('response from GETTING TRANSACTION POOL', r); + }), + ); + } } diff --git a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets-zk.service.ts b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets-zk.service.ts index 5bcbf1dc98..2c425391df 100644 --- a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets-zk.service.ts +++ b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets-zk.service.ts @@ -15,7 +15,6 @@ export class BenchmarksWalletsZkService { readonly updates$ = this.updates.asObservable(); - loadO1js(): void { this.loadScript(); } diff --git a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.component.html b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.component.html index d81ef32cf1..57ae83e92c 100644 --- a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.component.html +++ b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.component.html @@ -1,7 +1,8 @@
- -
+ +
diff --git a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.component.ts b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.component.ts index 39b36dc31f..a09f7ed0ef 100644 --- a/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.component.ts +++ b/frontend/src/app/features/benchmarks/wallets/benchmarks-wallets.component.ts @@ -4,6 +4,7 @@ import { StoreDispatcher } from '@shared/base-classes/store-dispatcher.class'; import { AppSelectors } from '@app/app.state'; import { filter, skip } from 'rxjs'; import { BenchmarksWalletsZkService } from '@benchmarks/wallets/benchmarks-wallets-zk.service'; +import { MinaNode } from '@shared/types/core/environment/mina-env.type'; @Component({ selector: 'mina-benchmarks-wallets', @@ -14,7 +15,9 @@ import { BenchmarksWalletsZkService } from '@benchmarks/wallets/benchmarks-walle }) export class BenchmarksWalletsComponent extends StoreDispatcher implements OnInit, OnDestroy { - constructor(private zkService: BenchmarksWalletsZkService) {super();} + isWebNode: boolean = false; + + constructor(private zkService: BenchmarksWalletsZkService) { super(); } ngOnInit(): void { this.zkService.loadO1js(); @@ -23,6 +26,10 @@ export class BenchmarksWalletsComponent extends StoreDispatcher implements OnIni } private listenToActiveNodeChange(): void { + this.select(AppSelectors.activeNode, (node: MinaNode) => { + this.isWebNode = node.isWebNode; + this.detect(); + }, filter(Boolean)); this.select(AppSelectors.activeNode, () => { this.dispatch(BenchmarksWalletsGetWallets, { initialRequest: true }); }, filter(Boolean), skip(1)); diff --git a/frontend/src/app/shared/types/core/environment/mina-env.type.ts b/frontend/src/app/shared/types/core/environment/mina-env.type.ts index 7d6cb73d38..c1e529f71e 100644 --- a/frontend/src/app/shared/types/core/environment/mina-env.type.ts +++ b/frontend/src/app/shared/types/core/environment/mina-env.type.ts @@ -2,7 +2,6 @@ export interface MinaEnv { production: boolean; configs: MinaNode[]; identifier?: string; - webNodeKey?: string; hideToolbar?: boolean; hideNodeStats?: boolean; globalConfig?: { diff --git a/frontend/src/assets/environments/webnode.js b/frontend/src/assets/environments/webnode.js new file mode 100644 index 0000000000..91ba243879 --- /dev/null +++ b/frontend/src/assets/environments/webnode.js @@ -0,0 +1,19 @@ +export default { + production: true, + globalConfig: { + features: { + 'dashboard': [], + 'block-production': ['won-slots'], + 'nodes': ['overview', 'live', 'bootstrap'], + 'mempool': [], + 'benchmarks': ['wallets'], + }, + canAddNodes: false, + }, + configs: [ + { + name: 'Web Node', + isWebNode: true, + }, + ], +}; diff --git a/frontend/src/assets/webnode/.gitignore b/frontend/src/assets/webnode/.gitignore index aa054e2d62..f735b09de9 100644 --- a/frontend/src/assets/webnode/.gitignore +++ b/frontend/src/assets/webnode/.gitignore @@ -1,3 +1,4 @@ #.gitignore circuit-blobs pkg +web-node-secrets.json diff --git a/frontend/src/environments/environment.ts b/frontend/src/environments/environment.ts index 1aa4df76b7..5f8c81e001 100644 --- a/frontend/src/environments/environment.ts +++ b/frontend/src/environments/environment.ts @@ -3,7 +3,6 @@ import { MinaEnv } from '@shared/types/core/environment/mina-env.type'; export const environment: Readonly = { production: false, identifier: 'Dev FE', - webNodeKey: '', globalConfig: { features: { dashboard: [], @@ -11,7 +10,6 @@ export const environment: Readonly = { state: ['actions'], network: ['messages', 'connections', 'blocks', 'topology', 'node-dht', 'graph-overview', 'bootstrap-stats'], snarks: ['scan-state', 'work-pool'], - 'testing-tool': ['scenarios'], resources: ['memory'], 'block-production': ['won-slots'], mempool: [], diff --git a/frontend/src/index.html b/frontend/src/index.html index 26abb901d1..2fa62e1940 100644 --- a/frontend/src/index.html +++ b/frontend/src/index.html @@ -29,17 +29,11 @@