Snapshot of the decentralized-web stack at the point of the resolver+Theseus rebuild deploy. Includes: - Argus (BNS engine + resolver daemon + Sia gateway) - AriadneResolver (Windows Inno installer bundle + Android APK sources + Firefox extension) - TheseusNavigator (Electron browser) - site/ (silentmode.st content, deployed to Sia at bns/silentmode/) - design docs, roadmap, protocol spec Secrets excluded via .gitignore: Argus/sia-s3.json, Argus/wallets.json, Argus/ca/*.key,*.crt. Build outputs, node_modules, and bundled runtimes also excluded. Shipped hashes on dl.silentmode.st at this commit: AriadneResolver-Setup-0.1.0.exe 5bcb216eef31ea28ed767e4134ab74bd5ac69dfbd365fd249e9e6938e55c986a TheseusNavigator-Setup-0.0.1.exe 7c735e88bad2da3347145adba3016c8f626a18b8422289c8c6ba471972e2952b TheseusNavigator-0.0.1-portable.exe 008fd84445babeabb401b2bca40ea9466b24b0e6d6c85104da7640c5c5c84521 ariadne-v0.2.apk 635c8f04d44ef855a8390b9eeddb8cd2d50622e81cc4e5004e8daffc1bb0425c
122 lines
4.7 KiB
Markdown
122 lines
4.7 KiB
Markdown
# Running your own Fulcrum — and why the resolver wants you to
|
|
|
|
Referenced from `src/registrar-config.js` (`REGISTRAR.selfHosted`).
|
|
|
|
## The problem this solves
|
|
|
|
Public electrum servers listen on **non-standard ports**: 50004 and 62002. On
|
|
2026-07-27 all three configured chipnet servers went TCP-closed from one machine
|
|
at the same instant, while `:443` stayed perfectly reachable. That is the
|
|
signature of a firewall or VPN policy, not an outage — and it is the normal
|
|
condition on corporate networks, on some mobile carriers, and behind many
|
|
consumer VPNs.
|
|
|
|
The consequence is worse than it sounds. Every server in the list shares the same
|
|
two ports, so **one rule takes down the entire resolver**: no availability
|
|
search, no registration, no record updates, for that user, everywhere the
|
|
software runs — website, extension, Theseus, Ariadne.
|
|
|
|
A server on 443 is indistinguishable from ordinary HTTPS traffic and is
|
|
essentially never blocked. **One server on 443 is worth more than three more on
|
|
50004.**
|
|
|
|
## The second reason: not trusting one server
|
|
|
|
A single electrum server is a trusted third party. It cannot forge a
|
|
registration — that needs a real CashTokens genesis whose commitment matches the
|
|
name — but it can **omit** one. Because the protocol rule is *"first valid REG
|
|
wins"*, a hidden REG makes a taken name look available: the buyer pays, mints a
|
|
duplicate certificate, and every other resolver rejects it.
|
|
|
|
`ElectrumPool.unionHistory` defends against exactly this by taking the **union**
|
|
of beacon history across every server that answers, and reporting which servers
|
|
were short. Union rather than quorum, because omission is the attack: a server
|
|
showing you *more* history is giving you more truth, and two stale servers must
|
|
not be able to outvote one honest one.
|
|
|
|
**So running your own server is not a centralisation trade.** Your server is the
|
|
fast, unblockable path; the public ones stay in the list as cross-checks. The
|
|
union means your own server cannot quietly hide a registration from you either.
|
|
|
|
## Configuration
|
|
|
|
```js
|
|
// src/registrar-config.js
|
|
selfHosted: "wss://bns.example.st:443",
|
|
```
|
|
|
|
That is all. The pool connects in parallel, prefers earlier entries, fails over
|
|
automatically, and unions the history regardless of order.
|
|
|
|
## Running Fulcrum
|
|
|
|
Fulcrum indexes a full node; you need both.
|
|
|
|
1. **Bitcoin Cash Node** with the indexes Fulcrum needs:
|
|
```
|
|
txindex=1
|
|
server=1
|
|
rpcuser=…
|
|
rpcpassword=…
|
|
chipnet=1 # or omit for mainnet
|
|
```
|
|
|
|
2. **Fulcrum**, pointed at it. The part that matters here is the **WSS port on
|
|
443**:
|
|
```
|
|
bitcoind = 127.0.0.1:8332
|
|
rpcuser = …
|
|
rpcpassword = …
|
|
ssl = 0.0.0.0:50002
|
|
wss = 0.0.0.0:443 # <- the one that survives restrictive networks
|
|
cert = /etc/letsencrypt/live/bns.example.st/fullchain.pem
|
|
key = /etc/letsencrypt/live/bns.example.st/privkey.pem
|
|
```
|
|
|
|
3. **A real certificate.** Browsers will not open a `wss://` connection with a
|
|
self-signed cert, and the failure is opaque — it surfaces as a generic
|
|
WebSocket error with no indication that the certificate is the cause. Use
|
|
Let's Encrypt.
|
|
|
|
4. **Binding 443 needs privilege.** Either `setcap
|
|
'cap_net_bind_service=+ep'` on the Fulcrum binary, or terminate TLS at nginx
|
|
and proxy to Fulcrum's plain WS port. The nginx route is usually easier
|
|
because it shares 443 with the rest of the site:
|
|
```nginx
|
|
location /electrum {
|
|
proxy_pass http://127.0.0.1:50003;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection "upgrade";
|
|
proxy_read_timeout 3600s; # electrum connections are long-lived
|
|
}
|
|
```
|
|
Then `selfHosted: "wss://bns.example.st:443/electrum"`.
|
|
|
|
## Verifying it
|
|
|
|
```bash
|
|
# reachable at all?
|
|
curl -sk -o /dev/null -w "%{http_code}\n" https://bns.example.st:443
|
|
|
|
# does it speak electrum?
|
|
cd Argus && node --input-type=module -e "
|
|
import WebSocket from 'ws';
|
|
import { Electrum } from './src/lib/electrum.js';
|
|
const el = await new Electrum('wss://bns.example.st:443', WebSocket).connect();
|
|
console.log(await el.call('server.version', ['probe','1.4.2']));
|
|
console.log('height:', (await el.call('blockchain.headers.subscribe')).height);
|
|
el.close(); process.exit(0);"
|
|
```
|
|
|
|
The second command is the one that matters — a server can answer HTTPS and still
|
|
not be a working electrum endpoint.
|
|
|
|
## Note for the browser
|
|
|
|
The register page can only reach electrum over **WSS**. It cannot open raw TCP,
|
|
so it can never talk to a P2P node directly, and it cannot use a plain-TCP
|
|
electrum port. Every entry in the list must be `wss://`. This is also why
|
|
SPV-grade *verification* (headers + merkle proofs over electrum) is the right
|
|
target for the web client rather than direct-to-node SPV — see
|
|
`Decentralized.DNS/DESIGN-trustless-purchase.md`.
|