Skip to content

Latest commit

History

67 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

namebitcoin-kernel/browser-node
version0.0.1
descriptionA Bitcoin testnet4 node's validation core running in a browser tab.
networktestnet4
homepagehttp://bitcoin-kernel.com/browser-node/
licenseAGPL-3.0-or-later
machine_readable_manifest./manifest.json
agent_guide./AGENTS.md
built_on
bitcoin-kernel/node
@bitcoin-desktop/schema (vendored under engine/)
acts
idnameruns_on
1
bootstrap UTXO from a torrented snapshot
local-server
idnameruns_on
3
validate a block forward
github-pages
idnameruns_on
4
follow the chain
github-pages
idnameruns_on
5
live header feed over a WS-to-TCP bridge
local-server
idnameruns_on
6
parse Core's dumptxoutset snapshot
github-pages

bitcoin-kernel / browser-node

A Bitcoin testnet4 node's validation core, running in a browser tab.

Bootstrap a UTXO set from a torrented or Bitcoin Core assumeUTXO snapshot, validate blocks forward against it (scripts, signatures, fees, all consensus rules), follow the chain by applying each block to the UTXO set, and live-sync the header chain from a real peer over a WebSocket-to-TCP bridge — all in the tab. The pure-JS consensus engine (@bitcoin-desktop/schema) and the browser-node design (bitcoin-kernel/node) do the work.

Live demo:http://bitcoin-kernel.com/browser-node/ (use buttons ③ ④ ⑥; ① ⑤ need a local server) ▶ Run the node (capstone):http://bitcoin-kernel.com/browser-node/node.html — a live dashboard that runs the whole pipeline (validation works on Pages; live header sync needs the local bridge)

Status: demo / proof-of-concept. Machine-readable manifest: manifest.json. Agent guide: AGENTS.md.

What it does — six acts

#ActProvesRuns onVerified
Bootstrap UTXO from a torrented snapshota snapshot fetched over WebTorrent/HTTP streams into a sharded coin viewlocal server250k coins in 0.11s; full scale 14.1M = 3.23 GB / 9.7s
Validate a block forwardone real block fully validated (scripts, BIP143 sigs, fees, maturity, witness commitment)GitHub Pagesblock #26000, 16/16 rules, 45ms; rejects a 1‑sat tamper
Follow the chainconsecutive blocks validated, applying UTXO updates so later blocks spend earlier outputs; linkage checkedGitHub Pagesblocks 26000–26020, UTXO 249→1,361, 1.1s
Live feed over a WS↔TCP bridgethe tab speaks p2p over a bridge to a real peer, syncs + fully validates the header chain (PoW, BIP94, reorg), tails the tip, and persists to OPFSlocal server141,671 headers genesis→tip in 5.8s; reload resumes from OPFS in 1.7s
Parse Core's dumptxoutset snapshotCore's real assumeUTXO snapshot (v2 compressed format) parsed in-tab and used as a validating coin viewGitHub Pagesfull 811 MB file → 13,870,119 coins, 40/40 match gettxout; block #120001 validated, 85ms
Persist the UTXO set (OPFS)the RAM-resident coin view is checkpointed to OPFS and resumes from disk on reloadGitHub Pages16,913 coins → 2.5 MB checkpoint (17ms); reload resumes in 11ms
WASM signature verificationa WASM libsecp256k1 backend swapped in via setVerifyBackend, gated by verdict-equivalenceGitHub Pagesblock #26000: ~1,161 → ~4,895 verifies/s (4.2× at block level), verdicts identical
Run the node in a Web Worker (scale)engine + WASM secp + UTXO store + OPFS sync-handles run off the main thread, so validation/checkpoints don't freeze the UIGitHub Pagesfollow 21 blocks in a Worker: UI responsive (16 ms frame gap) vs frozen on the main thread (~1063 ms)
SwiftSync — stateless validationset-consistency via a 32-byte accumulator (add created, subtract spent) instead of the ~25 GB UTXO setGitHub Pagesblocks 26000–26020 cancel to ZERO with 32 bytes of state; a fabricated spend is detected; 72 ms
SwiftSync at scalethe full real UTXO set committed via the accumulator with set-state held at 32 bytes, not 25 GBGitHub PagesNode: 14.1M coins → 0.9 GB RSS (the file), 32-byte commitment; tab: 3M coins streamed in the worker → 32 bytes, UI responsive
SwiftSync hintsreconstruct the UTXO set from blocks + a tiny hints file (no spend processing), verified by the accumulatorGitHub Pages26000–26020: 516-byte hints (~25 B/block; whole chain ≈ 3.3 MB) → 1,361-coin set rebuilt → accumulator ZERO ✓

Acts ③ ④ ⑥ are fully static and work on GitHub Pages. Acts ① (torrent seeding) and ⑤ (the bridge) need a local server — see below.

Run it

On GitHub Pages (no install)

Open http://bitcoin-kernel.com/browser-node/ and click ③, ④, ⑥.

Locally

node serve.mjs # static server + HTTP Range on http://localhost:8088 (zero deps)# open http://localhost:8088 -> acts ②③④⑥ work

Act ① (WebTorrent):

node tools/gen-snapshot.mjs 250000 snapshot.ndjson # generate a synthetic UTXO snapshot
npm install # webtorrent
node serve.mjs &# webseed host
node seed.mjs # seeds + writes magnet.txt, then click ①

Act ⑤ (live feed) — needs a testnet4 peer; a local bitcoind -testnet4 (P2P :48333) works:

npm install # ws
node bridge.mjs # ws://localhost:8334 -> 127.0.0.1:48333# or point elsewhere: PEER_HOST=seed.testnet4.bitcoin.sprovoost.nl node bridge.mjs# then click ⑤

Tests (self-contained, committed data only)

npm test# validate #26000, adversarial tamper, follow 26000–26020, parse + validate #120001

Architecture

index.html the ten acts, explained (the showcase)
node.html the capstone: a running-node dashboard (orchestrates the worker + live feed)
fullchain.html full-chain SwiftSync run: stream blocks from genesis through the accumulator (32-byte state)
sharded-utxo-browser.js ShardedUtxo — coin view sharded past V8's 16.7M Map cap
validate-forward.js load engine + coin view, validate one block forward
follow-chain.js applyBlock() + followChain() — validate a run, update the UTXO set
dumptxoutset.js parser for Bitcoin Core's dumptxoutset v2 compressed snapshot format
live-feed.js connect + syncToTip + tail (header sync over the bridge)
opfs-header-store.js persist the header chain to OPFS (main-thread async) — resume on reload
opfs-coins-store.js checkpoint the UTXO set (ShardedUtxo) to OPFS — resume on reload
wasm-secp.js WASM libsecp256k1 backend (tiny-secp256k1 wasm) for setVerifyBackend
secp256k1.wasm the libsecp256k1 binary (1.2 MB — the one large file in the repo)
node-worker.js the validation core in a Web Worker (engine + WASM secp + UTXO + OPFS sync handles)
swiftsync/ the repo's SwiftSync accumulator (vendored) — stateless set-consistency, 32-byte state
peer-ws.js WsPeer — Bitcoin p2p over a WebSocket (browser transport)
engine/ vendored @bitcoin-desktop/schema: consensus engine + schemas + stores
serve.mjs zero-dep static server (local)
seed.mjs WebTorrent seeder for act ① (optional, needs webtorrent)
bridge.mjs WebSocket-to-TCP bridge for act ⑤ (optional, needs ws)
tools/gen-snapshot.mjs generate a synthetic UTXO snapshot for act ①
data/ small committed fixtures (see Data & provenance)

Data & provenance

All fixtures are small and derived from real testnet4 data via a Bitcoin Core node (no third-party APIs):

FileWhatOrigin
data/block-26000.hex, data/block-120001.hexraw blocksbitcoin-cli getblock <hash> 0
data/snapshot-26000.ndjsonblock 26000's prevoutsgetblock <hash> 3 (verbosity-3 prevouts)
data/range.json, data/range-seed.ndjsonblocks 26000–26020 + pre-run prevoutsgetblock raw + verbosity-3
data/utxo-prefix.datfirst 1 MB of utxo-testnet4-120000.data real Core dumptxoutset snapshot (the full file is ~811 MB; only a prefix is committed)
data/snapshot-120001.ndjsonblock 120001's pre-snapshot prevoutsextracted by parsing the Core .dat with dumptxoutset.js
data/testnet4.jsongenesis header + retarget vectorsfrom @bitcoin-desktop/schema

The synthetic snapshot for act ① is not committed; generate it with tools/gen-snapshot.mjs.

Trust model

The bridge and the torrent/HTTP transports are untrusted — they cannot forge valid blocks or headers, because the tab validates everything (PoW, difficulty, scripts, signatures, fees). Their only powers are withholding and eclipsing. assumeUTXO trusts the snapshot's UTXO set until a background re-validation from genesis (not included in this demo) confirms it.

Not done yet

  • Full hints-based stateless IBD — the memory ceiling is gone (act ⑫ / tools/swiftsync-commit.mjs: the full 14.1M-coin UTXO set commits with 32 bytes of state), and SwiftSync is wired into the running node (act ⑪ + node.html). The deepest remaining piece is a complete stateless forward-validation over a large range / genesis→tip: generate a SwiftSync hints file (<100 MB, WebTorrent-distributed), stream blocks + prevout data, and validate holding only the accumulator + a bounded working set — a full IBD that never materializes the UTXO set. Large snapshots/hints go via WebTorrent, never git.

License & attribution

AGPL-3.0-or-later. Built on bitcoin-kernel/node and @bitcoin-desktop/schema (vendored under engine/, unmodified except import-path rewrites). See NOTICE.

About

A Bitcoin testnet4 node's validation core in a browser tab: bootstrap from a torrented or Core assumeUTXO snapshot, validate blocks forward, follow the chain, and live-sync headers over a WS-to-TCP bridge.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages