upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorbitflash-maintainer <noreply@bitflash.invalid>2026-08-26 22:41:53 +0000
committerbitflash-maintainer <noreply@bitflash.invalid>2026-08-26 22:41:53 +0000
commitbbe04dc8c96b4c4766d2771d3438233bf82687c0 (patch)
tree62e5a1febfb8e9bc38d133ac7981e9ef93918484 /docs
parent991853fa55a749d28d6f9e507ce72b289df92785 (diff)
parent9e39a50d1f110020b0841d31e4b931aa877cc448 (diff)
Merge upstream v1.2.19 into the fork
Merges upstream tag v1.2.19 (9e39a50) into merge/upstream-1.2.18 (991853f). Unlike the 1.2.15->1.2.18 replay, bc3de30 is a true ancestor of our branch via a9b4f89, so this is an ordinary three-way merge with merge-base bc3de30. Delta: 36 files, +3265/-163, the Tor onion transport (managed Tor, signed direct onion endpoints, onion-only dial mode) and the nHDNext restore fix. src/main.cpp, main.h, script.cpp/h and db.cpp/h are byte-identical between the two tags, and the poll() socket loop carries no diff hunks, so the merge is consensus-neutral and the soak-tested socket paths are unchanged. relay/ is untouched; the payout ledger (rpc.cpp) is untouched. 7 conflict blocks in 6 files, resolved as follows. Makefile -- VERSION. Ours: stays 1.2.19+sec with the naming comment updated, so artifacts from this tree cannot be mistaken for the upstream release. src/Makefile, src/makefile.mingw -- HEADERS list. Ours (no market.h) plus their tor.h. NODE_OBJS auto-merged correctly: no market.o, tor.o present. src/selftest.cpp -- known-tests list. Union: payout-ledger (ours) and managed-tor (theirs). src/main_gui.cpp -- one block. Our /dumpaddresses kept; their BtfStopManagedTor() on the StartNode failure path taken. The /rvrelay pin, /noannounce and the marketplace removal auto-merged and were verified intact. src/nostr.cpp -- two blocks in ResolveDescriptor. Signature takes both out-params (our fExchangeOk, their rawOut). The body keeps our drain-to-EOSE read -- returning early poisons the pooled socket for the next caller -- and adds their rawOut capture. Our TLS 1.2 floor (SSL_CTX_set_min_proto_version) is untouched by this merge; upstream 1.2.19 still has no floor of its own. Upstream's release commit also added four build logs and a compiled Python cache (build-1219.log, build-17.log, build-appimage.log, build-node.log, scripts/__pycache__/bitflash_chain.cpython-313.pyc). Removed here; they are build output, not source.
Diffstat (limited to 'docs')
-rw-r--r--docs/mining-calculator.md22
-rw-r--r--docs/pool-directory.md18
-rw-r--r--docs/release-verification.md18
-rw-r--r--docs/rendezvous.md72
-rw-r--r--docs/site.md115
-rw-r--r--docs/tor.md159
6 files changed, 386 insertions, 18 deletions
diff --git a/docs/mining-calculator.md b/docs/mining-calculator.md
index 352eea1..e6cb61b 100644
--- a/docs/mining-calculator.md
+++ b/docs/mining-calculator.md
@@ -84,3 +84,25 @@ The script is intentionally standalone so the same math can later back a
84website widget or status dashboard. Until a public price exists, a website 84website widget or status dashboard. Until a public price exists, a website
85calculator should keep price as a manual field and label fiat profit as 85calculator should keep price as a manual field and label fiat profit as
86speculative. 86speculative.
87
88## Website Fields
89
90A public calculator should ask for:
91
92- miner hashrate and unit;
93- power draw in watts;
94- electricity price per kWh;
95- pool fee percent;
96- optional BTF price;
97- either current Bitflash difficulty or current network hashrate.
98
99The output should separate:
100
101- estimated BTF per day;
102- estimated gross fiat revenue, if a manual price was provided;
103- electricity cost;
104- net profit/loss;
105- the difficulty/hashrate assumptions used.
106
107Never present the fiat number as a market quote unless it comes from a real
108public market. Before that exists, label it as a manual scenario.
diff --git a/docs/pool-directory.md b/docs/pool-directory.md
index 76269b9..ff0640a 100644
--- a/docs/pool-directory.md
+++ b/docs/pool-directory.md
@@ -26,6 +26,10 @@ The generated output contains:
26- `index.html`: human-readable ranking page. 26- `index.html`: human-readable ranking page.
27- `pools.json`: machine-readable API for `api.bitflash.network/pools.json`. 27- `pools.json`: machine-readable API for `api.bitflash.network/pools.json`.
28 28
29The website is a convenience layer, not a consensus or discovery dependency.
30Nodes discover pools through Nostr descriptors and `.btf`; a missing website
31must not stop mining or pool operation.
32
29When a source is an HTTP(S) `pool_status.json`, the directory links to a 33When a source is an HTTP(S) `pool_status.json`, the directory links to a
30`pool_rounds.json` proof file next to it. That file records the block height, 34`pool_rounds.json` proof file next to it. That file records the block height,
31block hash, coinbase txid, coinbase value, pool fee, total shares, per-address 35block hash, coinbase txid, coinbase value, pool fee, total shares, per-address
@@ -41,3 +45,17 @@ Ranking order is intentionally simple:
41 45
42An entry is considered online when the source says the pool is running and its 46An entry is considered online when the source says the pool is running and its
43status file is no more than 120 seconds old. 47status file is no more than 120 seconds old.
48
49## Recommended Hostnames
50
51Use:
52
53```text
54pool.bitflash.network human-readable pool directory
55api.bitflash.network/pools.json
56status.bitflash.network relay/node health, not pool ranking
57docs.bitflash.network operator setup guide
58```
59
60The GUI may use the API as a shortcut for humans, but it should keep the
61existing decentralized pool discovery path as the source of truth.
diff --git a/docs/release-verification.md b/docs/release-verification.md
index 32de74f..b8eaf5e 100644
--- a/docs/release-verification.md
+++ b/docs/release-verification.md
@@ -34,6 +34,16 @@ From a shell with `curl` or `wget`, `sha256sum` and `gpg`:
34scripts/verify-release.sh latest 34scripts/verify-release.sh latest
35``` 35```
36 36
37The public release host should expose latest-file aliases for convenience:
38
39```text
40https://releases.bitflash.network/SHA256SUMS
41https://releases.bitflash.network/SHA256SUMS.asc
42```
43
44Those aliases must point at the current versioned directory. They do not replace
45signature verification; they only make the common manual path shorter.
46
37For a specific release: 47For a specific release:
38 48
39```bash 49```bash
@@ -71,6 +81,14 @@ Publish, alongside the assets, `SHA256SUMS` and `SHA256SUMS.asc`, and update
71is ever rotated, announce the new fingerprint clearly and update the embedded 81is ever rotated, announce the new fingerprint clearly and update the embedded
72key in `verify-release.sh`. 82key in `verify-release.sh`.
73 83
84For Windows releases with managed Tor built in, run `make windows-tor`. It
85creates `Bitflash-*-windows-with-tor.zip` by downloading the Tor Expert Bundle,
86checking the pinned SHA256 in `scripts/package-windows-tor.sh`, optionally
87verifying the Tor Project `.asc` signature, and placing `tor/tor.exe` next to
88`Bitflash.exe`. For release builds, run `TOR_VERIFY_GPG=required make
89windows-tor` so the signature check is mandatory. Include that zip in
90`SHA256SUMS` like any other release asset.
91
74## Why this matters 92## Why this matters
75 93
76`SHA256SUMS` alone protects against a broken download, but not against someone 94`SHA256SUMS` alone protects against a broken download, but not against someone
diff --git a/docs/rendezvous.md b/docs/rendezvous.md
index ac8e598..68b5df3 100644
--- a/docs/rendezvous.md
+++ b/docs/rendezvous.md
@@ -18,11 +18,16 @@ A connection to a `.btf` service has three layers:
181. **Discovery (Nostr).** The service publishes a signed descriptor as a Nostr 181. **Discovery (Nostr).** The service publishes a signed descriptor as a Nostr
19 event. A caller fetches it by the service public key and verifies the 19 event. A caller fetches it by the service public key and verifies the
20 signature. The descriptor says which rendezvous relay the service is waiting 20 signature. The descriptor says which rendezvous relay the service is waiting
21 at and which encryption key to use. 21 at, which encryption key to use, and optionally which Tor hidden service can
22 be dialed directly.
222. **Rendezvous (TCP).** Caller and service both connect out to the same relay 232. **Rendezvous (TCP).** Caller and service both connect out to the same relay
23 and are paired by public key. Neither needs an inbound port or a public IP. 24 and are paired by public key. Neither needs an inbound port or a public IP.
24 After pairing the relay is a blind byte pipe. 25 After pairing the relay is a blind byte pipe.
253. **Encrypted channel (X25519 + XChaCha20-Poly1305).** Over the paired pipe the 263. **Direct onion fallback bypass.** If the descriptor carries a valid signed
27 `.onion:port` endpoint and the caller is running with Tor mode, the caller
28 tries that endpoint before using rendezvous. This removes the rendezvous
29 relay from the data path for peers that choose to run hidden services.
304. **Encrypted channel (X25519 + XChaCha20-Poly1305).** Over the paired pipe the
26 caller and service run an ephemeral to static handshake and then exchange 31 caller and service run an ephemeral to static handshake and then exchange
27 authenticated frames. The relay sees only ciphertext. 32 authenticated frames. The relay sees only ciphertext.
28 33
@@ -107,6 +112,8 @@ The default rendezvous port is `8434`.
107The descriptor is a JSON object, signed with the identity key over a domain 112The descriptor is a JSON object, signed with the identity key over a domain
108separated digest of its own fields. 113separated digest of its own fields.
109 114
115Legacy descriptor:
116
110```json 117```json
111{ 118{
112 "v": 2, 119 "v": 2,
@@ -118,7 +125,22 @@ separated digest of its own fields.
118} 125}
119``` 126```
120 127
121The signed digest is: 128Onion-capable descriptor:
129
130```json
131{
132 "v": 3,
133 "pubkey": "<hex 32-byte x-only identity key>",
134 "enc": "<hex 32-byte X25519 public key>",
135 "meeting_node": "host:port",
136 "onion": "<56-char-v3-name>.onion:8433",
137 "created": <unix seconds>,
138 "sig": "<legacy v2 signature>",
139 "sig3": "<signature over the onion-capable digest>"
140}
141```
142
143The legacy signed digest is:
122 144
123``` 145```
124digest = SHA256( ".btf-descriptor-v2" 146digest = SHA256( ".btf-descriptor-v2"
@@ -128,17 +150,37 @@ digest = SHA256( ".btf-descriptor-v2"
128 || created (8 bytes, big endian) ) 150 || created (8 bytes, big endian) )
129``` 151```
130 152
131The signature is a deterministic BIP340 Schnorr signature (no auxiliary 153`sig` is kept on v3 descriptors so old nodes can still resolve and dial through
132randomness) over `digest` by the identity key. 154the rendezvous relay. The onion-capable digest is:
155
156```
157digest3 = SHA256( ".btf-descriptor-v3-onion"
158 || pubkey[32]
159 || enc (raw bytes of the string)
160 || meeting_node (raw bytes of the string)
161 || onion (raw bytes of the normalized string)
162 || created (8 bytes, big endian) )
163```
164
165`sig` and `sig3` are deterministic BIP340 Schnorr signatures (no auxiliary
166randomness) over their respective digests by the identity key.
133 167
134**Verification** (untrusted input, must never throw): parse the JSON, require all 168**Verification** (untrusted input, must never throw): parse the JSON, require all
135fields with the right types, confirm `pubkey` equals the address being resolved, 169fields with the right types, confirm `pubkey` equals the address being resolved,
136recompute the digest, and verify the Schnorr signature. Any failure rejects the 170recompute the digest, and verify the Schnorr signature. Any failure rejects the
137descriptor. 171descriptor.
138 172
173If `onion` is present, readers accept it only when it is a normalized v3 onion
174endpoint and `sig3` verifies. A bad or tampered onion field is ignored; the v2
175descriptor can still be used for rendezvous fallback if `sig` verifies.
176
139`created` lets a reader prefer the freshest descriptor when more than one is 177`created` lets a reader prefer the freshest descriptor when more than one is
140seen. A node only publishes a descriptor once it has actually registered at a 178seen. A node without a direct onion endpoint only publishes a descriptor once it
141`meeting_node`, so it never advertises a relay it cannot be reached at. 179has actually registered at a `meeting_node`, so it never advertises a relay it
180cannot be reached at. A node with a direct onion endpoint may publish before
181rendezvous registration using `meeting_node = "rendezvous-pending"`; Tor peers
182can still dial the signed onion endpoint, and rendezvous becomes fallback once
183registration succeeds.
142 184
143## 6. Rendezvous transport 185## 6. Rendezvous transport
144 186
@@ -243,8 +285,9 @@ tunnel.
243 not published anywhere. 285 not published anywhere.
244- **Forward secrecy.** The caller's per connection ephemeral key means a later 286- **Forward secrecy.** The caller's per connection ephemeral key means a later
245 compromise of the service encryption key does not decrypt past sessions. 287 compromise of the service encryption key does not decrypt past sessions.
246- **IP privacy.** Neither side needs a public IP or an inbound port. The observable 288- **IP privacy.** Neither side needs a public IP or an inbound port for
247 network fact is that each side has a TCP connection to a relay. 289 rendezvous. With a signed `.onion` endpoint, the reachable side exposes only a
290 Tor hidden service and the relay is not in the peer connection path.
248 291
249## 10. Threat model and limitations 292## 10. Threat model and limitations
250 293
@@ -265,6 +308,11 @@ tunnel.
265 unreachable, discovery stalls until one is reachable again. Relay TLS is 308 unreachable, discovery stalls until one is reachable again. Relay TLS is
266 verified, which closes a man in the middle path on discovery, but availability 309 verified, which closes a man in the middle path on discovery, but availability
267 still rests on the relay set. 310 still rests on the relay set.
311- **Direct onion needs Tor.** With `-managedtor`, Bitflash starts a Tor process,
312 writes a local hidden-service config, and advertises the generated onion
313 endpoint. With `-onionservice`, an operator can still run Tor manually and
314 provide the endpoint. In both cases Tor owns the hidden-service private key and
315 uptime.
268 316
269## 11. Wire reference 317## 11. Wire reference
270 318
@@ -273,9 +321,9 @@ tunnel.
273| `.btf` Base32 alphabet | `abcdefghijklmnopqrstuvwxyz234567`, no padding | 321| `.btf` Base32 alphabet | `abcdefghijklmnopqrstuvwxyz234567`, no padding |
274| Address payload | `pubkey[32] || checksum[2]`, 55 Base32 chars | 322| Address payload | `pubkey[32] || checksum[2]`, 55 Base32 chars |
275| Address checksum | `SHA256(".btf-checksum-v1" || pubkey)[0..2]` | 323| Address checksum | `SHA256(".btf-checksum-v1" || pubkey)[0..2]` |
276| Descriptor domain sep | `.btf-descriptor-v2` | 324| Descriptor domain sep | `.btf-descriptor-v2`; optional onion sep `.btf-descriptor-v3-onion` |
277| Descriptor version | `2` | 325| Descriptor version | `2`; `3` when a signed onion endpoint is present |
278| Descriptor signature | BIP340 Schnorr, deterministic (no aux rand) | 326| Descriptor signature | BIP340 Schnorr, deterministic (no aux rand), v3 keeps `sig` plus `sig3` |
279| Nostr descriptor event | kind `38501`, `d = btf-descriptor-2` | 327| Nostr descriptor event | kind `38501`, `d = btf-descriptor-2` |
280| Nostr relay event | kind `38502`, `d = btf-relay-2` | 328| Nostr relay event | kind `38502`, `d = btf-relay-2` |
281| Nostr pool event | kind `38503`, `d = btf-pool-2` | 329| Nostr pool event | kind `38503`, `d = btf-pool-2` |
diff --git a/docs/site.md b/docs/site.md
new file mode 100644
index 0000000..9526a61
--- /dev/null
+++ b/docs/site.md
@@ -0,0 +1,115 @@
1# Public Site Contract
2
3The public Bitflash sites are generated from this repository. If a deployed
4page and the source disagree, the deployed page is stale.
5
6## Canonical Navigation
7
8Every public page should use the same top navigation:
9
10| label | target |
11|---|---|
12| home | `https://bitflash.network/` |
13| code | `https://git.bitflash.network/bitflash/bitflash` |
14| docs | `https://docs.bitflash.network/` |
15| downloads | `https://releases.bitflash.network/` |
16| explorer | `https://explorer.bitflash.network/` |
17| status | `https://status.bitflash.network/` |
18
19The `code` link intentionally points at the repository, not the Forgejo
20instance root. A visitor choosing "code" wants the source tree.
21
22## Documentation Pages To Publish
23
24The docs index should expose these source files:
25
26| page | source | why it matters |
27|---|---|---|
28| Manual | `README.md` | run, mine, recover, operate |
29| Key derivation and address format | `docs/derivation.md` | independent wallet recovery |
30| Release verification | `docs/release-verification.md` | pinned signing-key flow |
31| Dependencies | `docs/dependencies.md` | pinned secp256k1/RandomX supply chain |
32| Rendezvous and .btf addressing | `docs/rendezvous.md` | network design and caveats |
33| Tor mode | `docs/tor.md` | `-tor`, `-socks`, onion relay operation |
34| Fair launch verifier | `docs/fair-launch.md` | no-premine launch audit |
35| UTXO set commitment | `docs/utxo-commitment.md` | deterministic supply/root audit |
36| UTXO inclusion proofs | `docs/utxo-proofs.md` | proof for one unspent output |
37| Mining calculator | `docs/mining-calculator.md` | local WhatToMine-style estimates |
38| Public pool directory | `docs/pool-directory.md` | `pool_status.json`, `pools.json`, ranking |
39
40## Release Mirror Aliases
41
42Each release remains under its versioned directory:
43
44```text
45https://releases.bitflash.network/v1.2.19/SHA256SUMS
46https://releases.bitflash.network/v1.2.19/SHA256SUMS.asc
47```
48
49The release root should also alias the latest files:
50
51```text
52https://releases.bitflash.network/SHA256SUMS
53https://releases.bitflash.network/SHA256SUMS.asc
54https://releases.bitflash.network/Bitflash-latest-windows.zip
55https://releases.bitflash.network/Bitflash-latest-x86_64.AppImage
56https://releases.bitflash.network/bitflash-node-latest-x86_64
57```
58
59The aliases are convenience only. Verification must still require the pinned
60release key documented in `docs/release-verification.md`.
61
62## Static Explorer
63
64`scripts/build-explorer.py` writes a static explorer with no backend:
65
66```text
67index.html
68style.css
69explorer.js
70logo.png
71blocks.json
72block/<height>.json
73```
74
75Serve it with a strict content policy:
76
77```text
78default-src 'none';
79img-src 'self';
80style-src 'self';
81script-src 'self';
82connect-src 'self';
83base-uri 'none';
84form-action 'none';
85frame-ancestors 'none';
86```
87
88The viewer must never use `innerHTML` for chain data. A malicious transaction
89must be rendered as text, not interpreted as markup.
90
91## Cache Policy
92
93Recommended defaults:
94
95| path | cache |
96|---|---|
97| HTML pages | `public, max-age=0, must-revalidate` |
98| `status.json` | `no-store` |
99| `blocks.json`, `block/*.json` | `public, max-age=0, must-revalidate` |
100| release assets | `public, max-age=14400, must-revalidate` |
101| `SHA256SUMS`, signatures, keys | `public, max-age=0, must-revalidate` |
102
103## Security Headers
104
105Recommended for all static pages:
106
107```text
108Strict-Transport-Security: max-age=31536000; includeSubDomains
109X-Content-Type-Options: nosniff
110Referrer-Policy: no-referrer
111Permissions-Policy: interest-cohort=(), geolocation=(), camera=(), microphone=()
112```
113
114Forgejo has its own application headers and should not blindly inherit the
115static-site CSP.
diff --git a/docs/tor.md b/docs/tor.md
index 087c822..0016f8b 100644
--- a/docs/tor.md
+++ b/docs/tor.md
@@ -25,15 +25,106 @@ bitflash -tor=127.0.0.1:9150
25bitflash -tor=[::1]:9050 25bitflash -tor=[::1]:9050
26``` 26```
27 27
28For a SOCKS5 proxy that is not Tor, use `-socks` directly:
29
30```bash
31bitflash -socks=127.0.0.1:9050
32bitflash -socks=[::1]:9050
33```
34
35If both `-tor` and `-socks` are present, Tor mode wins and the node prints a
36warning. That keeps a command line with `-tor` from silently becoming a custom
37proxy route.
38
39## Managed Tor mode
40
41`-managedtor` starts a Tor process for this node, writes a local `torrc`, creates
42a v3 hidden service for the normal Bitflash P2P listener, routes outbound
43discovery through that Tor instance, and signs the generated `.onion:8433`
44endpoint into the node's `.btf` descriptor.
45
46```bash
47bitflash -managedtor
48```
49
50Without a value, Bitflash looks for Tor in this order:
51
521. `tor/tor.exe` or `tor/tor` beside the Bitflash binary;
532. `tor.exe` or `tor` beside the Bitflash binary;
543. `tor.exe` or `tor` on `PATH`.
55
56Windows releases can also be built as `Bitflash-*-windows-with-tor.zip`. That
57package includes the official Tor Expert Bundle under `tor/`, so the first path
58above exists immediately after extraction and `bitflash -managedtor` needs no
59separate Tor install.
60
61The bundled-Tor package is created by:
62
63```bash
64make windows-tor
65```
66
67The packaging script verifies a pinned SHA256 for the downloaded Tor Expert
68Bundle before copying it into the release directory. When `gpg` is available it
69also verifies the matching `.asc` signature against the pinned Tor Browser
70Developers signing-key fingerprint. Release builds should use
71`TOR_VERIFY_GPG=required make windows-tor` to make that second check mandatory.
72The Tor binary is bundled; the runtime data directory, hidden-service key, and
73control cookie are still created under the user's Bitflash data directory.
74
75To point at a specific Tor executable:
76
77```bash
78bitflash -managedtor=/opt/tor/bin/tor
79bitflash -managedtor=C:\Tor Browser\Browser\TorBrowser\Tor\tor.exe
80```
81
82Managed Tor writes its state under the Bitflash data directory:
83
84```text
85managed-tor/
86 torrc
87 data/
88 onion-service/
89```
90
91The private key for the onion address lives in `managed-tor/onion-service/`.
92Back up that directory if you want the same onion address after moving the node.
93Delete it only if you intentionally want a fresh onion endpoint.
94
95`-managedtor` takes precedence over `-tor` and `-socks`, because it must choose
96the local SOCKS port it starts. Diagnostics report the current managed Tor
97state, including the SOCKS port and onion endpoint once Tor has generated it.
98
28When Tor mode is enabled: 99When Tor mode is enabled:
29 100
30- outbound Nostr relay dials use Tor; 101- outbound Nostr relay dials use Tor;
31- outbound `.btf` rendezvous relay dials use Tor; 102- outbound `.btf` rendezvous relay dials use Tor;
103- outbound direct peer dials prefer signed `.onion` endpoints when a peer
104 advertises one;
32- destination names are sent to Tor as SOCKS5 domain-name CONNECT requests, so 105- destination names are sent to Tor as SOCKS5 domain-name CONNECT requests, so
33 the local DNS resolver does not see them; 106 the local DNS resolver does not see them;
34- direct `.onion` dials are refused unless a SOCKS5/Tor proxy is enabled; 107- direct `.onion` dials are refused unless a SOCKS5/Tor proxy is enabled;
35- plain HTTP external-IP probes are skipped. 108- plain HTTP external-IP probes are skipped.
36 109
110Tor mode affects outbound discovery and relay dials. It does not encrypt
111`wallet.dat`, hide mining rewards on-chain, or change the `.btf` identity. A
112relay still sees the TCP client that connected to it; with Tor mode that client
113is the Tor exit or onion circuit endpoint instead of the user's direct IP.
114
115## What to test
116
117Use the public status page only as a rough health check. To prove the local node
118is using Tor/SOCKS, test from the node machine:
119
120```bash
121bitflash -tor -debug
122```
123
124Then confirm in `debug.log` that Nostr and rendezvous dials report the proxy
125path. A DNS leak test should show no local resolver lookup for relay hostnames:
126the SOCKS5 request uses the domain-name form and asks the proxy to resolve it.
127
37## Onion rendezvous relay 128## Onion rendezvous relay
38 129
39An operator can expose a Bitflash rendezvous relay as a Tor hidden service. The 130An operator can expose a Bitflash rendezvous relay as a Tor hidden service. The
@@ -69,16 +160,72 @@ bitflash -operator -tor \
69 -announcerelay=exampleexampleexampleexampleexampleexampleexampleexample.onion:8434 160 -announcerelay=exampleexampleexampleexampleexampleexampleexampleexample.onion:8434
70``` 161```
71 162
72## Full-node hidden service 163## Manual direct full-node hidden service
73 164
74The legacy P2P listener still binds to port `8433`. You can expose it through 165Managed Tor is the preferred path for ordinary nodes. Operators can still expose
75Tor manually: 166the P2P listener through a separately managed Tor service:
76 167
77```text 168```text
78HiddenServiceDir /var/lib/tor/bitflash-node/ 169HiddenServiceDir /var/lib/tor/bitflash-node/
79HiddenServicePort 8433 127.0.0.1:8433 170HiddenServicePort 8433 127.0.0.1:8433
80``` 171```
81 172
82Current automatic peer discovery is `.btf`/rendezvous based, not onion-address 173After restarting Tor, read the generated onion name:
83gossip. Treat direct full-node onion access as an operator/admin tool unless a 174
84future release adds first-class onion peer advertisements. 175```bash
176sudo cat /var/lib/tor/bitflash-node/hostname
177```
178
179Then start Bitflash with Tor outbound enabled and advertise that hidden service:
180
181```bash
182bitflash -tor \
183 -onionservice=exampleexampleexampleexampleexampleexampleexampleexample.onion:8433
184```
185
186That onion endpoint is signed into this node's self-certifying `.btf`
187descriptor. New peers that resolve the descriptor and also run with `-tor` try
188the `.onion:8433` P2P connection first. If it fails, they fall back to the
189ordinary encrypted rendezvous path. Older nodes ignore the onion field and still
190use the rendezvous relay because the descriptor keeps the legacy signature too.
191
192If the node has `-onionservice` but has not registered at any rendezvous relay
193yet, it can still publish an onion-capable descriptor with
194`meeting_node = rendezvous-pending`. Tor-capable peers can dial the hidden
195service directly from that descriptor. Rendezvous becomes a fallback, not a
196precondition for being discoverable.
197
198This means rendezvous relays stop being the only way to reach a node that has
199published a hidden service. They remain useful bootstrap/fallback infrastructure,
200but an already-discovered onion-capable peer can be reached directly over Tor.
201
202Tor owns the private key under `HiddenServiceDir`; back it up if you want the
203onion name to stay stable.
204
205## Release smoke test
206
207After building a Windows binary with managed Tor support, run the two-node smoke
208test before cutting a release:
209
210```powershell
211powershell -ExecutionPolicy Bypass -File scripts\smoke-managed-tor-onion.ps1 `
212 -Bitflash .\src\bitflash.exe `
213 -Tor C:\path\to\tor.exe
214```
215
216The script creates two temporary datadirs, starts node A with `-managedtor`,
217waits for it to publish its `.btf` identity and generated `.onion` endpoint,
218then starts node B with its own `-managedtor`, `-oniononly`, and
219`-connectbtf=<node-a>`. It passes only when node B logs that it connected to
220node A `via direct onion`; rendezvous fallback cannot satisfy the test.
221
222By default the script waits 120 seconds after node A's descriptor self-resolves
223before it starts node B. Tor can create the local `hostname` before the hidden
224service descriptor is visible enough for client circuits, and early dials often
225fail with SOCKS5 reply `0x01`. Override this with `-OnionWarmupSec N` when
226testing a slow or already-warmed Tor environment.
227
228This test still uses Nostr for descriptor discovery, because that is how nodes
229learn each other's signed `.btf` descriptors. It does not require a Bitflash
230rendezvous relay to carry the P2P connection: once the descriptor includes the
231signed onion endpoint, the actual node connection goes directly through Tor.