Bootstrap a UTXO set from a torrented or Bitcoin Core assumeUTXO snapshot, validate blocks
forward, follow the chain, and live-sync headers β all in this tab, on the bitcoin-kernel engine.
π How it works Β· β Verify the UTXO set (SwiftSync, 32 bytes) Β· βΆ Run the node Β· from genesis Β· or the acts below.
Acts β’ β£ β₯ work here on GitHub Pages. Acts β (WebTorrent seeding) and β€ (the live p2p bridge) need a local server β see the README.
Validate the next real testnet4 block (#26000) forward against its coin view β full consensus: prevout resolution, scripts/signatures (BIP143), fees, coinbase amount, maturity, witness commitment. The bitcoin-kernel engine runs in this tab; the coin view holds the 28 real prevouts the block spends.
Validate a run of consecutive real blocks (26000β26020), applying each to the UTXO set so the next block can spend its outputs, and verifying linkage block-to-block. This is a node's inner loop β the step from "accepts a block" to "follows the chain." This range is a consolidation cascade: most inputs spend coins created earlier in the run, so it only works if the apply step is correct.
A browser can't open raw TCP, so the tab speaks the Bitcoin p2p protocol over a WebSocket to a thin local bridge that relays frames to a real testnet4 peer (here, our own synced node). The tab does the version/verack handshake, syncs the whole header chain from genesis, and fully validates every header (PoW, BIP94 difficulty, linkage, most-work reorg) β then tails the live tip. The bridge is untrusted: it can't forge a valid header. The chain is persisted to OPFS, so a reload resumes from disk instead of re-syncing from genesis.
dumptxoutset snapshotParse the real Bitcoin Core snapshot we torrented (utxo-testnet4-120000.dat, the v2
compressed format) directly in the tab, then forward-validate the first post-snapshot block (#120001) against the
coin view it produces. This is the bridge from a Core assumeUTXO snapshot to a usable, validating node β and the
ultimate parser proof: real signatures only verify if every decompressed amount and script is exactly right.
The coin view lives in RAM (fast synchronous lookups), and is checkpointed to OPFS β the same model Bitcoin Core uses (flush the chainstate periodically, not every block). Build a coin view from the Core snapshot, checkpoint it, then resume it from disk on reload β no re-parsing. This is UTXO-set persistence; at full 14M-coin scale the same code moves into a Web Worker with sync access handles (see README).
Signature verification is the bottleneck for inscription-flood blocks (~14k sigs each). The engine's
default is pure-JS secp256k1; this swaps in a WASM libsecp256k1 backend via the engine's
setVerifyBackend hook. Gated by a consensus check: WASM must agree with pure-JS on every verdict β
you don't swap consensus crypto on faith.
At full 14M-coin scale, validating inscription-flood blocks (~14k sigs) and writing multi-GB UTXO checkpoints would freeze the tab. The fix: run the engine, the WASM secp backend, the UTXO set, and OPFS sync access handles (Worker-only, the fast I/O path) inside a Web Worker. Below: the same validation runs in the Worker (UI stays responsive) and on the main thread (UI freezes) β measured by the largest gap between animation ticks.
The full UTXO set is ~25 GB β too big for a tab. SwiftSync
removes the need to hold it: since all outputs β all inputs = the UTXO set, you feed every created output (+)
and spent input (β) into a constant-size accumulator. With the start + terminal snapshots, a valid chain
cancels to zero β proving no double-spends or fabricated coins, with 32 bytes of state instead of 25 GB.
This is the repo's own SwiftSync accumulator (verified across all of testnet4), run here over a real block range.
The proof that this breaks the ceiling: streaming the real full testnet4 UTXO set (14,129,063 coins,
826 MB) through the accumulator commits it with RSS flat at ~0.9 GB (the input file) β the set-state
never leaves 32 bytes, vs ~25 GB to hold it (tools/swiftsync-commit.mjs, commitment
af37b01dβ¦). Below, the same accumulator streams millions of outpoints in the worker (UI stays
responsive) to show the 32-byte state holds at scale, in the tab.
The full SwiftSync flow: generate a compact hints file (which outputs survive), reconstruct the UTXO set from blocks + hints with no spend processing (fast, parallelizable), and verify it with the 32-byte accumulator. The hints are tiny (~25 bytes/block β the whole testnet4 chain β a few MB), and they carry no trust: wrong hints just fail the accumulator check.