|  | 
|  | 1 | +# OpenMina Webnode Implementation | 
|  | 2 | + | 
|  | 3 | +This document covers the WebAssembly (WASM) build target of OpenMina located in | 
|  | 4 | +`node/web/`. | 
|  | 5 | + | 
|  | 6 | +## Overview | 
|  | 7 | + | 
|  | 8 | +The webnode compiles the full OpenMina node to WebAssembly for browser | 
|  | 9 | +execution. It includes block production, transaction processing, SNARK | 
|  | 10 | +verification, and WebRTC-based P2P networking. | 
|  | 11 | + | 
|  | 12 | +### Design Goals | 
|  | 13 | + | 
|  | 14 | +- Run the full node stack in browsers without plugins | 
|  | 15 | +- Maintain compatibility with the main OpenMina implementation | 
|  | 16 | +- Support block production with browser-based proving | 
|  | 17 | +- Provide JavaScript API for web applications | 
|  | 18 | + | 
|  | 19 | +## Architecture | 
|  | 20 | + | 
|  | 21 | +### WASM Target | 
|  | 22 | + | 
|  | 23 | +Builds as both `cdylib` and `rlib` crate types. Code is conditionally compiled | 
|  | 24 | +with `#[cfg(target_family = "wasm")]` guards. | 
|  | 25 | + | 
|  | 26 | +#### Build Process | 
|  | 27 | + | 
|  | 28 | +```bash | 
|  | 29 | +cd node/web | 
|  | 30 | +cargo +nightly build --release --target wasm32-unknown-unknown | 
|  | 31 | +wasm-bindgen --keep-debug --web --out-dir ../../frontend/src/assets/webnode/pkg ../../target/wasm32-unknown-unknown/release/openmina_node_web.wasm | 
|  | 32 | +``` | 
|  | 33 | + | 
|  | 34 | +Requires nightly toolchain and generates bindings for | 
|  | 35 | +`frontend/src/assets/webnode/pkg/`. | 
|  | 36 | + | 
|  | 37 | +For complete setup instructions including circuit downloads and frontend | 
|  | 38 | +configuration, see [local-webnode.md](../local-webnode.md). | 
|  | 39 | + | 
|  | 40 | +### Threading | 
|  | 41 | + | 
|  | 42 | +Browser threading constraints require specific adaptations: | 
|  | 43 | + | 
|  | 44 | +#### Rayon Setup | 
|  | 45 | + | 
|  | 46 | +`init_rayon()` in `rayon.rs` configures the thread pool using | 
|  | 47 | +`num_cpus.max(2) - 1` threads. Must be called before SNARK verification. | 
|  | 48 | + | 
|  | 49 | +#### Task Spawning | 
|  | 50 | + | 
|  | 51 | +- `P2pTaskSpawner`: Uses `wasm_bindgen_futures::spawn_local()` | 
|  | 52 | +- `P2pTaskRemoteSpawner`: Routes tasks to main thread via | 
|  | 53 | +  `thread::start_task_in_main_thread()` because WebRTC APIs are main-thread only | 
|  | 54 | + | 
|  | 55 | +## Features | 
|  | 56 | + | 
|  | 57 | +Provides the same functionality as the native node: | 
|  | 58 | + | 
|  | 59 | +- Transaction validation and application | 
|  | 60 | +- Ledger state management | 
|  | 61 | +- SNARK verification using browser-compiled circuits | 
|  | 62 | +- Consensus participation | 
|  | 63 | +- RPC interface for web applications | 
|  | 64 | + | 
|  | 65 | +### Block Production | 
|  | 66 | + | 
|  | 67 | +Supports block production with: | 
|  | 68 | + | 
|  | 69 | +- Plain text or encrypted private keys (parsed in `parse_bp_key()`) | 
|  | 70 | +- Custom coinbase receivers | 
|  | 71 | +- Browser-based SNARK proving via `BlockProver::make()` | 
|  | 72 | + | 
|  | 73 | +### Networking | 
|  | 74 | + | 
|  | 75 | +#### WebRTC P2P Layer | 
|  | 76 | + | 
|  | 77 | +- **Transport**: WebRTC DataChannels for browser-to-browser communication | 
|  | 78 | +- **Protocol**: Pull-based networking (see [P2P README](../p2p/readme.md)) | 
|  | 79 | +- **Default Peer**: | 
|  | 80 | +  `/2bjYBqn45MmtismsAYP9rZ6Xns9snCcNsN1eDgQZB5s6AzY2CR2/https/webrtc3.webnode.openmina.com/443` | 
|  | 81 | +- **Channels**: 8 distinct DataChannels for different protocol types (see | 
|  | 82 | +  [P2P README](../p2p/readme.md#channels)) | 
|  | 83 | + | 
|  | 84 | +#### Network Configuration | 
|  | 85 | + | 
|  | 86 | +```rust | 
|  | 87 | +initial_peers: Vec<P2pConnectionOutgoingInitOpts> | 
|  | 88 | +peer_discovery: !self.p2p_no_discovery | 
|  | 89 | +max_peers: Some(100) | 
|  | 90 | +``` | 
|  | 91 | + | 
|  | 92 | +## Implementation Details | 
|  | 93 | + | 
|  | 94 | +### Key Files | 
|  | 95 | + | 
|  | 96 | +#### `lib.rs` - Main Entry Point | 
|  | 97 | + | 
|  | 98 | +- **`main()`**: Automatic WASM initialization | 
|  | 99 | +- **`run()`**: Primary node startup function | 
|  | 100 | +- **`build_env()`**: Build information export | 
|  | 101 | +- **`parse_bp_key()`**: Block producer key parsing | 
|  | 102 | + | 
|  | 103 | +#### `node/builder.rs` - Node Construction | 
|  | 104 | + | 
|  | 105 | +- **`NodeBuilder`**: Node configuration | 
|  | 106 | +- **Configuration Methods**: P2P setup, block production, verification | 
|  | 107 | +- **Default Peers**: Single hardcoded WebRTC peer for bootstrap | 
|  | 108 | + | 
|  | 109 | +#### `node/mod.rs` - Type Definitions | 
|  | 110 | + | 
|  | 111 | +- **Type Aliases**: `Node = openmina_node_common::Node<NodeService>` | 
|  | 112 | +- **Task Spawners**: P2P-specific spawning implementations for browser | 
|  | 113 | +  constraints | 
|  | 114 | + | 
|  | 115 | +#### `rayon.rs` - Threading Setup | 
|  | 116 | + | 
|  | 117 | +- **`init_rayon()`**: Required initialization for multi-threading | 
|  | 118 | +- **CPU Detection**: Automatic core count with minimum guarantees | 
|  | 119 | + | 
|  | 120 | +### JavaScript Interface | 
|  | 121 | + | 
|  | 122 | +#### Main Entry Point | 
|  | 123 | + | 
|  | 124 | +```javascript | 
|  | 125 | +const rpcSender = await run(blockProducerKey, seedNodesUrl, genesisConfigUrl); | 
|  | 126 | +``` | 
|  | 127 | + | 
|  | 128 | +- `blockProducerKey`: Optional string or `[encrypted, password]` array | 
|  | 129 | +- `seedNodesUrl`: Optional URL returning newline-separated peer addresses | 
|  | 130 | +- `genesisConfigUrl`: Optional URL returning binary genesis config (defaults to | 
|  | 131 | +  `DEVNET_CONFIG`) | 
|  | 132 | + | 
|  | 133 | +#### Setup | 
|  | 134 | + | 
|  | 135 | +- `console_error_panic_hook` enables panic traces in browser console | 
|  | 136 | +- `keep_worker_alive_cursed_hack()` prevents worker termination (wasm-bindgen | 
|  | 137 | +  issue #2945) | 
|  | 138 | + | 
|  | 139 | +### Performance | 
|  | 140 | + | 
|  | 141 | +- Parallel SNARK verification using `num_cpus.max(2) - 1` threads | 
|  | 142 | +- Circuit reuse for verification operations | 
|  | 143 | +- 100 peer connection limit configured in `P2pLimits` | 
|  | 144 | +- Statistics collection via `gather_stats()` when enabled | 
|  | 145 | + | 
|  | 146 | +## Dependencies | 
|  | 147 | + | 
|  | 148 | +**WASM-specific**: `wasm-bindgen`, `wasm-bindgen-futures`, `js-sys`, | 
|  | 149 | +`console_error_panic_hook`, `gloo-utils` | 
|  | 150 | + | 
|  | 151 | +**Core**: Standard OpenMina workspace crates plus `rayon` for threading | 
|  | 152 | + | 
|  | 153 | +## Known Issues | 
|  | 154 | + | 
|  | 155 | +- Worker lifecycle requires `keep_worker_alive_cursed_hack()` due to | 
|  | 156 | +  wasm-bindgen issue #2945 | 
|  | 157 | +- WebRTC operations restricted to main thread | 
|  | 158 | +- Careful initialization ordering required | 
|  | 159 | + | 
|  | 160 | +## Technical Debt | 
|  | 161 | + | 
|  | 162 | +- TODO in `setup_node()` for seed nodes refactoring | 
|  | 163 | +- Single hardcoded default peer | 
|  | 164 | +- Commented HTTP client and peer loading code in `builder.rs` | 
|  | 165 | + | 
|  | 166 | +## Usage | 
|  | 167 | + | 
|  | 168 | +```javascript | 
|  | 169 | +// Basic startup | 
|  | 170 | +const rpc = await run(); | 
|  | 171 | + | 
|  | 172 | +// With block producer | 
|  | 173 | +const rpc = await run("private-key"); | 
|  | 174 | +const rpc = await run([encryptedKey, "password"]); | 
|  | 175 | + | 
|  | 176 | +// With custom configuration | 
|  | 177 | +const rpc = await run(key, peersUrl, genesisUrl); | 
|  | 178 | + | 
|  | 179 | +// RPC access | 
|  | 180 | +const peers = await rpc.state().peers(); | 
|  | 181 | +const stats = await rpc.stats().sync(); | 
|  | 182 | +``` | 
|  | 183 | + | 
|  | 184 | +## Future Work | 
|  | 185 | + | 
|  | 186 | +- Split prover to its own WASM heap | 
|  | 187 | +  (https://github.com/openmina/openmina/issues/1128) | 
|  | 188 | +- API for zkApp integration | 
0 commit comments