Skip to content

Roadmap: browser-native Bitcoin node (epic) #1

Open

Description

@melvincarvalho

The tracking issue for building a browser-native Bitcoin node on the bitcoin-kernel engine. Background and the full architecture/perf model: bitcoin-kernel.github.io#1.

Principle: every step is gated by a benchmark

We do not build on guesses. Each milestone ships with a measured number, and the whole plan is re-checked against M0's results before we commit to the expensive parts.

Usable first, trustless later (resource tiers)

Opt into more resource to trust less. Tiers are designed in from day one, not bolted on.

Tier Does Cost Device
0 Lite headers + Neutrino wallet (BIP 157/158) ~100 MB, minutes phone
1 Validating assumeutxo snapshot, validate new blocks live a few GB laptop
2 Full backfill genesis to tip, fully trustless ~650 GB, lots of RAM desktop

Trust ladder: headers (PoW) -> filters/SPV (light) -> assumeutxo (one hash) -> backfill complete (trustless).

Three pillars

  1. Storage: OPFS, synchronous access handles in a Worker. (OPFS works on gh-pages with no special headers.)
  2. Compute: WASM-SIMD secp256k1 + Web Workers; UTXO set in RAM, no DB in the hot path.
  3. Networking: a small local WebSocket-to-TCP bridge. A browser cannot open raw TCP. WebRTC/WebTorrent block-swarming is a later decentralization layer, not the MVP.

Milestones

  • M0 — Benchmarks. Measure WASM-secp, SHA256, OPFS, and SharedArrayBuffer on real data before any app code. These numbers decide everything.
  • M1 — Headers + the bridge (Tier 0 foundation). Local TCP shim, headers-first sync to tip with full PoW/difficulty validation, persisted and resumable in OPFS.
  • M2 — Light wallet (Tier 0). BIP 158 filter scan backwards from tip; build a wallet's UTXO/history; verify inclusion via SPV.
  • M3 — assumeutxo (Tier 1). Load a hash-checked UTXO snapshot; validate new blocks forward (WASM workers, UTXO in RAM).
  • M4 — Backfill (Tier 2). Validate genesis to snapshot in the background; flip the UI from trusted snapshot to fully validated.
  • M5 — Durability / PWA. Persistent storage, installable, survives restart, resumes.

Known gh-pages gotchas to resolve along the way: SharedArrayBuffer needs COOP/COEP (service-worker workaround, or skip SAB initially); the TCP bridge is a separate local download, not hosted.

Sub-issues are filed per milestone, starting with M0. Non-goals: archival serving, mining, mempool/relay policy, matching native speed.

Activity

  1. melvincarvalho commented on Jun 18, 2026

    @melvincarvalho
    ContributorAuthor

    Progress: Tier 0 core runs in Node (testnet4).

    Decisions locked along the way: ESM .js only (no .mjs); built for mainnet + testnet4 via the network param, testnet4 first; the tip cross-check uses p2p peers, never a third-party explorer API.

    Next: M1.3 (OPFS store + resume + reorg/most-work), then M0.1 (the WASM-secp benchmark) before any block-validation work.

  2. melvincarvalho commented on Jun 18, 2026

    @melvincarvalho
    ContributorAuthor

    Model correction from M0.1 (#2), measured not estimated: WASM ECDSA verify is ~3,840/s (tiny-secp256k1), 16x the pure-JS engine but ~2.6x slower than the ~10k/s I'd assumed. Per-call JS↔WASM overhead dominates. Revised full-signature-verification estimate: ~7.5h on 24 cores (~8-15h realistic), not ~3h. The honest headline becomes "fully validated overnight," and batch verification + SIMD move to the critical path (each needs its own M0-style benchmark before block validation).

    Progress so far: M1.2 (#8) and M1.3 (#9) done — live testnet4 header sync, full validation, resume, most-work reorg, all headless-tested behind HeaderStore/HeaderSync interfaces (two swaps to the browser). M0.1 (#2) done. 14 unit tests green.

  3. melvincarvalho commented on Jun 18, 2026

    @melvincarvalho
    ContributorAuthor

    M2 (light wallet) core done, headless-proven.

    • src/wallet/wallet-scan.js — WalletScan: watch scriptPubKeys, scan a height range by BIP 158 compact filters, download only matching blocks (match-then-fetch, so filter false positives cost a fetch not correctness), build UTXO set + balance + history. Platform-agnostic like HeaderSync: depends only on codec + GcsFilter + three transport-agnostic fetchers.
    • Tests: BIP 158 primitive + WalletScan against the official BIP 158 vectors (real blocks/filters) + spend tracking. 18 unit tests green.
    • src/scan-testnet4.js — live Neutrino scan wired (sync headers → getcfilters → match → getdata matched blocks → balance/history).

    Honest finding (measured): 0/10 reachable public testnet4 peers advertise NODE_COMPACT_FILTERS (services=3081). Public testnet4 nodes rarely run blockfilterindex, so the live filter scan needs a filter-serving source (own node with -blockfilterindex=1 -peerblockfilters=1, or another filter source). The logic is proven against the official vectors regardless. This is an M0-style discovery worth a dedicated sub-issue.

    Session tally: M1.2, M1.3, M0.1, and M2-core done; 18 headless tests; live testnet4 header sync + resume + reorg working. The two open realities to weigh: (1) M0.1 says full validation is ~overnight not ~afternoon (batch/SIMD secp is the lever); (2) M2 live needs a filter source.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions