diff options
| author | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-05 22:46:52 +0000 |
|---|---|---|
| committer | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-05 22:46:52 +0000 |
| commit | ceae3d076b5ad11ee84729ae43f14e9312896646 (patch) | |
| tree | 7e9132aa871fdc01cb95268d2f5ea3bb11853ddf /docs/tor.md | |
| parent | be63e83d79e7e00e6b8ca889a70e6a19886aa1d8 (diff) | |
| parent | 66e0b9158d050c46b1ff2509faeee3f4573cac1c (diff) | |
Bring main onto the line this project actually ships
main had drifted to a history with no ancestor in common with the tree we
build and deploy. It sat at be63e83 (2026-08-09) with 28 commits; the shipped
line, deploy/soak-2026-08-21, had 383. The two shared nothing -- git
merge-base returns no result at all -- so anyone cloning this repository
landed on a default branch that was neither current nor related to the
running node.
The 28 commits on main were audited before this merge: every one is already
present in the tree by content, including the two that are hardest to see
because they were rewritten afterwards -- the payout reorg-safety work
(PayoutBlockStillOnChain, since evolved to re-check on every retry rather
than once at maturity) and the nostr relay certificate verification
(SSL_set1_host, now with a Windows root-store path). Nothing on main is lost
by this merge.
Recorded as a merge rather than a force-push: main only ever moves forward,
its old history stays reachable as the first parent, and this is revertible.
The tree is taken wholesale from the merged branch, so main's content is now
exactly what was built and tested.
What this brings onto main:
- compactblock: BIP152-style compact block relay ported from upstream 1.2.23,
primitives and unit test only, with the RAND_bytes failure path closed and
the reconstruction allocation bounded.
- upstream/main 17741d9: isolated testnet parameters and genesis, optional
2 MB large pages for RandomX. Mainnet genesis verified byte-identical
through upstream's BuildGenesisBlock() refactor.
- deploy: every image built on bookworm so binaries run on Debian 12, and the
container build now honours the RandomX and libsecp256k1 pins it had been
silently ignoring since before 1.2.15.
Gates at this tree: 15/15 selftests, compactblock's 17 checks, consensus
constants unchanged against e4f898c apart from the pre-existing
MAX_BLOCK_SIZE_GEN, mainnet genesis intact, money-log check ok.
Diffstat (limited to 'docs/tor.md')
| -rw-r--r-- | docs/tor.md | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/docs/tor.md b/docs/tor.md new file mode 100644 index 0000000..0016f8b --- /dev/null +++ b/docs/tor.md | |||
| @@ -0,0 +1,231 @@ | |||
| 1 | # Tor mode | ||
| 2 | |||
| 3 | Bitflash can route outbound discovery traffic through a local Tor SOCKS5 proxy. | ||
| 4 | This is transport plumbing only: it does not change consensus, wallet keys, | ||
| 5 | mining, `.btf` addresses, or the encrypted rendezvous protocol. | ||
| 6 | |||
| 7 | ## Client mode | ||
| 8 | |||
| 9 | Start Tor locally, then start Bitflash with: | ||
| 10 | |||
| 11 | ```bash | ||
| 12 | bitflash -tor | ||
| 13 | ``` | ||
| 14 | |||
| 15 | `-tor` is shorthand for: | ||
| 16 | |||
| 17 | ```bash | ||
| 18 | bitflash -socks=127.0.0.1:9050 | ||
| 19 | ``` | ||
| 20 | |||
| 21 | If Tor listens somewhere else: | ||
| 22 | |||
| 23 | ```bash | ||
| 24 | bitflash -tor=127.0.0.1:9150 | ||
| 25 | bitflash -tor=[::1]:9050 | ||
| 26 | ``` | ||
| 27 | |||
| 28 | For a SOCKS5 proxy that is not Tor, use `-socks` directly: | ||
| 29 | |||
| 30 | ```bash | ||
| 31 | bitflash -socks=127.0.0.1:9050 | ||
| 32 | bitflash -socks=[::1]:9050 | ||
| 33 | ``` | ||
| 34 | |||
| 35 | If both `-tor` and `-socks` are present, Tor mode wins and the node prints a | ||
| 36 | warning. That keeps a command line with `-tor` from silently becoming a custom | ||
| 37 | proxy route. | ||
| 38 | |||
| 39 | ## Managed Tor mode | ||
| 40 | |||
| 41 | `-managedtor` starts a Tor process for this node, writes a local `torrc`, creates | ||
| 42 | a v3 hidden service for the normal Bitflash P2P listener, routes outbound | ||
| 43 | discovery through that Tor instance, and signs the generated `.onion:8433` | ||
| 44 | endpoint into the node's `.btf` descriptor. | ||
| 45 | |||
| 46 | ```bash | ||
| 47 | bitflash -managedtor | ||
| 48 | ``` | ||
| 49 | |||
| 50 | Without a value, Bitflash looks for Tor in this order: | ||
| 51 | |||
| 52 | 1. `tor/tor.exe` or `tor/tor` beside the Bitflash binary; | ||
| 53 | 2. `tor.exe` or `tor` beside the Bitflash binary; | ||
| 54 | 3. `tor.exe` or `tor` on `PATH`. | ||
| 55 | |||
| 56 | Windows releases can also be built as `Bitflash-*-windows-with-tor.zip`. That | ||
| 57 | package includes the official Tor Expert Bundle under `tor/`, so the first path | ||
| 58 | above exists immediately after extraction and `bitflash -managedtor` needs no | ||
| 59 | separate Tor install. | ||
| 60 | |||
| 61 | The bundled-Tor package is created by: | ||
| 62 | |||
| 63 | ```bash | ||
| 64 | make windows-tor | ||
| 65 | ``` | ||
| 66 | |||
| 67 | The packaging script verifies a pinned SHA256 for the downloaded Tor Expert | ||
| 68 | Bundle before copying it into the release directory. When `gpg` is available it | ||
| 69 | also verifies the matching `.asc` signature against the pinned Tor Browser | ||
| 70 | Developers signing-key fingerprint. Release builds should use | ||
| 71 | `TOR_VERIFY_GPG=required make windows-tor` to make that second check mandatory. | ||
| 72 | The Tor binary is bundled; the runtime data directory, hidden-service key, and | ||
| 73 | control cookie are still created under the user's Bitflash data directory. | ||
| 74 | |||
| 75 | To point at a specific Tor executable: | ||
| 76 | |||
| 77 | ```bash | ||
| 78 | bitflash -managedtor=/opt/tor/bin/tor | ||
| 79 | bitflash -managedtor=C:\Tor Browser\Browser\TorBrowser\Tor\tor.exe | ||
| 80 | ``` | ||
| 81 | |||
| 82 | Managed Tor writes its state under the Bitflash data directory: | ||
| 83 | |||
| 84 | ```text | ||
| 85 | managed-tor/ | ||
| 86 | torrc | ||
| 87 | data/ | ||
| 88 | onion-service/ | ||
| 89 | ``` | ||
| 90 | |||
| 91 | The private key for the onion address lives in `managed-tor/onion-service/`. | ||
| 92 | Back up that directory if you want the same onion address after moving the node. | ||
| 93 | Delete it only if you intentionally want a fresh onion endpoint. | ||
| 94 | |||
| 95 | `-managedtor` takes precedence over `-tor` and `-socks`, because it must choose | ||
| 96 | the local SOCKS port it starts. Diagnostics report the current managed Tor | ||
| 97 | state, including the SOCKS port and onion endpoint once Tor has generated it. | ||
| 98 | |||
| 99 | When Tor mode is enabled: | ||
| 100 | |||
| 101 | - outbound Nostr 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; | ||
| 105 | - destination names are sent to Tor as SOCKS5 domain-name CONNECT requests, so | ||
| 106 | the local DNS resolver does not see them; | ||
| 107 | - direct `.onion` dials are refused unless a SOCKS5/Tor proxy is enabled; | ||
| 108 | - plain HTTP external-IP probes are skipped. | ||
| 109 | |||
| 110 | Tor 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 | ||
| 112 | relay still sees the TCP client that connected to it; with Tor mode that client | ||
| 113 | is the Tor exit or onion circuit endpoint instead of the user's direct IP. | ||
| 114 | |||
| 115 | ## What to test | ||
| 116 | |||
| 117 | Use the public status page only as a rough health check. To prove the local node | ||
| 118 | is using Tor/SOCKS, test from the node machine: | ||
| 119 | |||
| 120 | ```bash | ||
| 121 | bitflash -tor -debug | ||
| 122 | ``` | ||
| 123 | |||
| 124 | Then confirm in `debug.log` that Nostr and rendezvous dials report the proxy | ||
| 125 | path. A DNS leak test should show no local resolver lookup for relay hostnames: | ||
| 126 | the SOCKS5 request uses the domain-name form and asks the proxy to resolve it. | ||
| 127 | |||
| 128 | ## Onion rendezvous relay | ||
| 129 | |||
| 130 | An operator can expose a Bitflash rendezvous relay as a Tor hidden service. The | ||
| 131 | node does not create hidden services itself; Tor owns that configuration. | ||
| 132 | |||
| 133 | Example `torrc`: | ||
| 134 | |||
| 135 | ```text | ||
| 136 | HiddenServiceDir /var/lib/tor/bitflash-rendezvous/ | ||
| 137 | HiddenServicePort 8434 127.0.0.1:8434 | ||
| 138 | ``` | ||
| 139 | |||
| 140 | After restarting Tor, read the generated onion name: | ||
| 141 | |||
| 142 | ```bash | ||
| 143 | sudo cat /var/lib/tor/bitflash-rendezvous/hostname | ||
| 144 | ``` | ||
| 145 | |||
| 146 | Then run the relay on localhost/VPS as usual and announce the onion endpoint from | ||
| 147 | nodes that use Tor: | ||
| 148 | |||
| 149 | ```bash | ||
| 150 | bitflash -tor -rvrelay=exampleexampleexampleexampleexampleexampleexampleexample.onion:8434 | ||
| 151 | bitflash -tor -announcerelay=exampleexampleexampleexampleexampleexampleexampleexample.onion:8434 | ||
| 152 | ``` | ||
| 153 | |||
| 154 | For a pool operator that wants the pool descriptor to point at an onion | ||
| 155 | rendezvous relay, use both: | ||
| 156 | |||
| 157 | ```bash | ||
| 158 | bitflash -operator -tor \ | ||
| 159 | -rvrelay=exampleexampleexampleexampleexampleexampleexampleexample.onion:8434 \ | ||
| 160 | -announcerelay=exampleexampleexampleexampleexampleexampleexampleexample.onion:8434 | ||
| 161 | ``` | ||
| 162 | |||
| 163 | ## Manual direct full-node hidden service | ||
| 164 | |||
| 165 | Managed Tor is the preferred path for ordinary nodes. Operators can still expose | ||
| 166 | the P2P listener through a separately managed Tor service: | ||
| 167 | |||
| 168 | ```text | ||
| 169 | HiddenServiceDir /var/lib/tor/bitflash-node/ | ||
| 170 | HiddenServicePort 8433 127.0.0.1:8433 | ||
| 171 | ``` | ||
| 172 | |||
| 173 | After restarting Tor, read the generated onion name: | ||
| 174 | |||
| 175 | ```bash | ||
| 176 | sudo cat /var/lib/tor/bitflash-node/hostname | ||
| 177 | ``` | ||
| 178 | |||
| 179 | Then start Bitflash with Tor outbound enabled and advertise that hidden service: | ||
| 180 | |||
| 181 | ```bash | ||
| 182 | bitflash -tor \ | ||
| 183 | -onionservice=exampleexampleexampleexampleexampleexampleexampleexample.onion:8433 | ||
| 184 | ``` | ||
| 185 | |||
| 186 | That onion endpoint is signed into this node's self-certifying `.btf` | ||
| 187 | descriptor. New peers that resolve the descriptor and also run with `-tor` try | ||
| 188 | the `.onion:8433` P2P connection first. If it fails, they fall back to the | ||
| 189 | ordinary encrypted rendezvous path. Older nodes ignore the onion field and still | ||
| 190 | use the rendezvous relay because the descriptor keeps the legacy signature too. | ||
| 191 | |||
| 192 | If the node has `-onionservice` but has not registered at any rendezvous relay | ||
| 193 | yet, it can still publish an onion-capable descriptor with | ||
| 194 | `meeting_node = rendezvous-pending`. Tor-capable peers can dial the hidden | ||
| 195 | service directly from that descriptor. Rendezvous becomes a fallback, not a | ||
| 196 | precondition for being discoverable. | ||
| 197 | |||
| 198 | This means rendezvous relays stop being the only way to reach a node that has | ||
| 199 | published a hidden service. They remain useful bootstrap/fallback infrastructure, | ||
| 200 | but an already-discovered onion-capable peer can be reached directly over Tor. | ||
| 201 | |||
| 202 | Tor owns the private key under `HiddenServiceDir`; back it up if you want the | ||
| 203 | onion name to stay stable. | ||
| 204 | |||
| 205 | ## Release smoke test | ||
| 206 | |||
| 207 | After building a Windows binary with managed Tor support, run the two-node smoke | ||
| 208 | test before cutting a release: | ||
| 209 | |||
| 210 | ```powershell | ||
| 211 | powershell -ExecutionPolicy Bypass -File scripts\smoke-managed-tor-onion.ps1 ` | ||
| 212 | -Bitflash .\src\bitflash.exe ` | ||
| 213 | -Tor C:\path\to\tor.exe | ||
| 214 | ``` | ||
| 215 | |||
| 216 | The script creates two temporary datadirs, starts node A with `-managedtor`, | ||
| 217 | waits for it to publish its `.btf` identity and generated `.onion` endpoint, | ||
| 218 | then starts node B with its own `-managedtor`, `-oniononly`, and | ||
| 219 | `-connectbtf=<node-a>`. It passes only when node B logs that it connected to | ||
| 220 | node A `via direct onion`; rendezvous fallback cannot satisfy the test. | ||
| 221 | |||
| 222 | By default the script waits 120 seconds after node A's descriptor self-resolves | ||
| 223 | before it starts node B. Tor can create the local `hostname` before the hidden | ||
| 224 | service descriptor is visible enough for client circuits, and early dials often | ||
| 225 | fail with SOCKS5 reply `0x01`. Override this with `-OnionWarmupSec N` when | ||
| 226 | testing a slow or already-warmed Tor environment. | ||
| 227 | |||
| 228 | This test still uses Nostr for descriptor discovery, because that is how nodes | ||
| 229 | learn each other's signed `.btf` descriptors. It does not require a Bitflash | ||
| 230 | rendezvous relay to carry the P2P connection: once the descriptor includes the | ||
| 231 | signed onion endpoint, the actual node connection goes directly through Tor. | ||