# status and evidence ## what was verified All commands run from the repository root with Go 1.25+ and TinyGo 0.43 (Go 1.27 from `~/.local/goroot` where TinyGo needs it). | Check | Result | |---|---| | `go test ./...` | pass | | `go vet ./...` | pass | | `go test -race ./pkg/tunnel ./pkg/neutrino ./internal/e2e` | pass | | `tinygo build -target wasm -o bin/nostrino.wasm ./cmd/nostrino-wasm` | pass | | `tinygo build ./cmd/nostrino-bridge ./cmd/nostrino-neutrino` | pass | | wasm sync through torly + bridge + test node | tip 50, 51 filters; ~2.7 s relay, ~20 ms WebSocket | | IndexedDB reload (two wasm instances, fake-indexeddb) | second sync adds 0, same tip, local match still works | | wasm cancel mid-sync | settles as `cancelled`, bridge closes the session | | frozen reader / zero credit | 4 MiB write blocks, then unblocks on reset | | NIP-42 on a torly with auth required | endpoint-to-endpoint sync passes | | two relays, one dropping every event | stream continues on the other | | WebSocket data plane (bridge=) | e2e sync over the WS stream; both wasm smokes assert `transport=websocket` | | reorg to a different branch at height 6 | old filters replaced, new branch matches | | checkpoint at height 10 | starts at 10, verifies 11..tip, no filter below | | gateway presence + `nostrino-discover` | finds the URI, chains and node tip | | file store resume | second sync adds 0; tip and filters preserved | | dropped relay events | 512 KiB echo survives 1-in-9 drops | | profile JSON + difficulty/retarget/MTP | unit tests pass | Reproduce: ```sh make build wasm ./scripts/wasm-smoke.sh (cd /tmp && npm install fake-indexeddb) # once NODE_PATH=/tmp/node_modules ./scripts/idb-smoke.sh bin/nostrino-discover -relay wss://relay.example -chain btc ``` The smoke scripts start torly, the deterministic test node, the bridge and the wasm bundle under Node. They are the acceptance tests for the browser target. ## known gaps Ordered by what matters next. 1. **Pinned network data.** Mainnet checkpoint values and the real XBT parameters are not in the binary. `-profile` and `-checkpoint-*` accept them; the operator must obtain them from a trusted node and keep them current. A stale checkpoint only costs sync time; a wrong one is rejected on the first filter header. 2. **Streaming browser storage.** The IndexedDB store loads its indexes into memory on open. That is fine for a regtest chain and a recent-range wallet, but a full mainnet filter set (GB scale) needs a store that reads filters on demand. The `Store` interface is the seam; the sync loop should not change. 3. **First retarget after a checkpoint.** The window's first block is not stored, so that one boundary is accepted from the peer. Every later boundary is verified. A checkpoint that also pins the window's start would close this. 4. **Deep reorgs.** Fork search is bounded at 10,000 headers. A deeper reorg is refused rather than silently accepted, which is the safe failure; a mainnet wallet also needs the height it scans from. 5. **TLS termination for the bridge.** The WebSocket data plane is implemented, but the reference build listens in plain `ws://`. A public `wss://` endpoint needs a reverse proxy (or a later TLS listener) and the operator supplies its advertised URL with `-bridge-url`. 6. **Registry abuse and accuracy.** Presence is an unauthenticated public advertisement; the tip is from a handshake every five minutes and can be stale. There is no TTL enforcement beyond the relay's addressable-event replacement, no per-publisher rate on announcements, and discovery trusts the payload (the event signature and `d` tag are checked, but a gateway can lie about its tip). 7. **Quotas and accounting.** The bridge has a per-stream byte rate and a per-client session cap. There is no per-day quota, no per-IP limit, and no accounting to bill or block a heavy client. 8. **Relay auth for reads.** NIP-42 is answered and publications wait for the auth result. A relay that requires auth for REQ is not specially handled; torly gates writes only. 9. **Wallet and swap layers.** Out of scope for this repository: BIP32/BIP84, UTXO selection, HTLC scripts, signing, the swap state machine, the settlement deadline recomputation on resume, and the server-side swap record. The registry and the tunnel deliberately do not carry swap state. ## operational notes - The gateway key lives in `DATA/gateway.key` (0600), the URI in `DATA/gateway.uri`. - Torly's WebSocket idle timeout is 150 s; the native transport pings every 45 s and the listener reconnects with backoff. - Torly's maximum event is 128 KiB; the default 32 KiB frame produces about 55 KiB of encrypted content. - The bridge defaults to 4 MiB/s per direction and two streams per client; adjust with `-max-bytes-per-sec` and `-max-sessions-per-client`. - `nostrino-bridge -check -node ...` reports whether the node advertises `NODE_COMPACT_FILTERS`; an operator must still confirm `blockfilterindex=basic` and the filter index height. - The browser WebSocket stream has no portable socket read timeout; the bridge's idle bound and the WebSocket close/error events bound liveness. The P2P read deadline is advisory on that path. - The test node is a fixture, not a Bitcoin node.