upleb.uk

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

summaryrefslogtreecommitdiff
path: root/MINING_PLAN.md
diff options
context:
space:
mode:
authorYour Name <you@example.com>2026-05-19 14:25:18 +0530
committerYour Name <you@example.com>2026-05-19 14:25:18 +0530
commite366ceb336550a72c76efea4c98a2a08cca27bce (patch)
tree4b45ac6f6e97b6763f81aa6d4a9b968d23e41235 /MINING_PLAN.md
parent163b8badec9359373a8fc016c2b1fe9ee38e6406 (diff)
feat(mining): Bitcoin mining-for-bandwidth payment system
New modules: - mining_payment.c/h: hashprice calc (nbits->difficulty->sat/GH/s/day), share validation, client stats, allotment conversion (ms + bytes) - stratum_client.c/h: SV1 upstream pool connection (subscribe/authorize/submit) - stratum_proxy.c/h: Local SV1 TCP server for downstream miners, job broadcast - sw_miner.c/h: Software SHA256d miner (ESP32 CPU fallback) - asic_miner.c/h: ASIC detection stub (BM1366/BM1368 SPI) Config: - config.h/c: mining_payout_mode_t enum (auto/pool/upstream/proxy_only), stratum pool settings, mining port, hashprice override, sandbox mint access - Defaults fill nostr_seed_relays (8/8) and nostr_relays (4/4) with fast relays Integration into existing modules: - session.h/c: payment_method_t enum (CASHU/MINING/BYTES) - firewall.h/c: firewall_set_mining_port(), firewall_set_sandbox_mint_access() - tollgate_api.c: GET /mining/job, POST /mining/share, GET /mining/stats - tollgate_client.h/c: TG_CLIENT_MINING state, mining discovery tag parsing - tollgate_main.c: mining init in start_services(), stratum_client_tick() in loop - captive_portal.c: tabbed Cashu/Mine UI with live hashrate polling Unit tests (69 new assertions across 4 suites): - test_mining_payment (23 tests): nbits->difficulty, hashprice, client stats, allotment - test_stratum_proxy (21 tests): job set/get, stats, type validation - test_session_payment_method (12 tests): PAYMENT_METHOD enum, bytes/cashu methods - test_tollgate_client_mining (20 tests): mining tag parsing, discovery struct - test_firewall_sandbox (16 tests): client grant/revoke, max clients, setters Enhanced test stubs: - BaseType_t/pdPASS in freertos/task.h - lwip: sockets.h, etharp.h, prot/ip.h, prot/ip4.h, prot/tcp.h, netif.h - dns_server.h, esp_wifi_ap_get_sta_list.h Build fixes: - cvm_server.c: replace esp_timer_get_time() with xTaskGetTickCount(), fix process_relay_message() 3-arg call to 2-arg, add WS keepalive ping - stratum_proxy.c: widen task_name buffer 16->20 - sw_miner.c: add missing #include esp_random.h - nucula_src: save_proofs() moved to public in wallet.hpp Nostr relay updates: - nostr_seed_relays: +relay.anzenkodo.workers.dev, +nostr.koning-degraaf.nl, +knostr.neutrine.com, +nostr.einundzwanzig.space (8/8 slots) - nostr_relays: +relay.anzenkodo.workers.dev, +nostr.koning-degraaf.nl (4/4 slots) Squash-merge of feature/mining-payment (5 commits: c75230e..9d98ba1)
Diffstat (limited to 'MINING_PLAN.md')
-rw-r--r--MINING_PLAN.md357
1 files changed, 357 insertions, 0 deletions
diff --git a/MINING_PLAN.md b/MINING_PLAN.md
new file mode 100644
index 0000000..bb72d3c
--- /dev/null
+++ b/MINING_PLAN.md
@@ -0,0 +1,357 @@
1# Mining-for-Bandwidth Implementation Plan
2
3## Overview
4
5Add Bitcoin mining (Stratum v1 + v2) to the TollGate firmware so that devices earn internet access by mining real Bitcoin blocks. A BitAxe (ESP32-S3 + BM1366 ASIC) running TollGate firmware becomes a plug-and-play mesh node — no e-cash, Nostr identity, or prior setup required.
6
7## Design Decisions
8
9### Why real Bitcoin mining instead of arbitrary proof-of-work?
10
11The work must be **useful** — mining against a Stratum v2 block template means every share contributes to Bitcoin's security. Even at negligible hashrate (ESP32 software mining at ~10-50 kH/s), the work is real. With a BM1366 ASIC (~500 GH/s), the device produces meaningful hashrate.
12
13### Why Stratum v2 upstream + Stratum v1 local?
14
15- **SV2 upstream (to pool)**: Binary framing is bandwidth-efficient, Noise encryption prevents hash hijacking, and the encrypted tunnel uses minimal megabytes on the paid internet link
16- **SV1 local (to downstream miners)**: JSON-RPC is trivial to implement, no handshake overhead, works over local WiFi with negligible latency
17- BitAxe already has both implementations — we reuse them
18
19### Why Braiins Pool as default SV2 pool?
20
21- Native SV2 support with published authority pubkey
22- 0% PPLNS fee option
23- Lightning Network payouts (useful for converting mining revenue to e-cash)
24- The authority pubkey is known: `024e031a0b63c7885b19e48f76d49ddbcda9bf3d7f1d6b05df8b71569e2c2f7ff0`
25
26### Why dual payout mode (Lightning sats vs e-cash)?
27
28A TollGate's position in the mesh determines what it earns:
29
30| Position | Hashrate goes to | Earns |
31|----------|-----------------|-------|
32| Standalone (has direct internet) | Braiins pool | Lightning sats for operator |
33| Mesh node (upstream TollGate detected) | Upstream TollGate's proxy | e-cash / megabytes / minutes |
34| Relay (no ASIC, no internet) | Nothing locally | Just proxies for downstream miners |
35
36The `mining_payout_mode` config field controls this: `auto` (default) detects upstream TollGate and chooses accordingly.
37
38### Why mine with CPU too?
39
40UX. We don't care if CPU mining is profitable. A plain ESP32-S3 without an ASIC can still produce non-zero hashrate (~10-50 kH/s via hardware SHA256 accelerator). This means ANY ESP32 running TollGate firmware can bootstrap itself — even one byte per hour is better than zero.
41
42### Why sandbox mint access?
43
44Miners who earn bandwidth via hashrate should also reach the Cashu mint URLs the TollGate accepts. This way they can receive e-cash from mobile wallets without first having internet access. The firewall whitelists mint URLs for unauthenticated clients.
45
46### Why hashprice from block template?
47
48The conversion from hashrate → bandwidth needs a price signal:
49
50```
51hashprice = (block_subsidy * blocks_per_day) / (difficulty * 2^32) [sat/GH/day]
52allotment = (hashrate_ghs * hashprice_per_s * duration_s) / price_per_step * step_size
53```
54
55Calculating hashprice from the `nbits` field in the SV2 block template is automatic, requires no external API, and is always accurate. A config override (`hashprice_sats_per_ghs_day`) is available as fallback. A ContextVM MCP tool (`get_hashprice`) is planned for future dynamic pricing.
56
57### Why BitAxe as git submodule?
58
59The BitAxe ESP-Miner firmware (GPL-3.0) runs on the same ESP-IDF v5.x on ESP32-S3. It contains production-quality implementations of:
60- `components/stratum_v2/` — SV2 protocol + Noise handshake
61- `components/stratum/` — SV1 protocol
62- `components/asic/` — BM1366/BM1368 serial drivers
63
64Rather than copying code that will diverge, we reference it as a submodule and compile selected components.
65
66## Architecture
67
68```
69[Bitcoin SV2 Pool (Braiins)]
70 ↑ SV2 + Noise (encrypted, binary)
71[TollGate Gateway] (ESP32-S3, has internet via STA)
72 ├── stratum_client.c — SV2 upstream to Braiins (Noise handshake, job reception, share forwarding)
73 ├── stratum_proxy.c — Local SV1 TCP :3333 (distribute jobs, collect shares, per-IP hashrate meter)
74 ├── mining_payment.c — Share validation, hashprice calc, session_create() calls
75 ├── sw_miner.c — ESP32-S3 hardware SHA256 accelerator (~10-50 kH/s, always runs)
76 ├── asic_miner.c — BM1366/BM1368 via SPI (~500 GH/s, if detected)
77 ├── Existing: captive portal, Cashu, firewall, sessions, wifistr, CVM
78
79[TollGate Miner] (BitAxe ESP32-S3 + BM1366, no internet)
80 ├── SV1 client → connects to gateway's :3333 via local WiFi
81 ├── ASIC driver → BM1366 via SPI
82 ├── tollgate_client.c → mining mode (instead of Cashu payment)
83 └── Also runs its own AP for downstream devices
84
85[Plain ESP32 TollGate]
86 ├── SV1 client → connects to gateway's :3333
87 ├── sw_miner.c only (~10-50 kH/s)
88 └── Also runs its own AP for downstream devices
89```
90
91## Config Fields (config.json)
92
93```json
94{
95 "mining_enabled": true,
96 "mining_payout_mode": "auto",
97 "stratum_host": "v2.pool.braiins.com",
98 "stratum_port": 3333,
99 "stratum_user": "bc1q...TollGate",
100 "stratum_pass": "x",
101 "stratum_sv2_authority_pubkey": "024e031a0b63c7885b19e48f76d49ddbcda9bf3d7f1d6b05df8b71569e2c2f7ff0",
102 "stratum_fallback_host": "public-pool.io",
103 "stratum_fallback_port": 21496,
104 "mining_port": 3333,
105 "hashprice_sats_per_ghs_day": 0,
106 "mining_sandbox_mint_access": true
107}
108```
109
110| Field | Default | Description |
111|-------|---------|-------------|
112| `mining_enabled` | `false` | Enable mining subsystem |
113| `mining_payout_mode` | `"auto"` | `"auto"`, `"pool"`, `"upstream"`, `"proxy_only"` |
114| `stratum_host` | `"v2.pool.braiins.com"` | SV2 pool hostname |
115| `stratum_port` | `3333` | SV2 pool port |
116| `stratum_user` | `""` | Bitcoin/Lightning address for pool payout |
117| `stratum_pass` | `"x"` | Pool password |
118| `stratum_sv2_authority_pubkey` | Braiins key | Pool authority pubkey for Noise verification |
119| `stratum_fallback_host` | `"public-pool.io"` | SV1 fallback pool hostname |
120| `stratum_fallback_port` | `21496` | SV1 fallback pool port |
121| `mining_port` | `3333` | Local mining proxy listen port |
122| `hashprice_sats_per_ghs_day` | `0` | Manual hashprice override (0 = auto from nbits) |
123| `mining_sandbox_mint_access` | `true` | Allow unauthenticated clients to reach mint URLs |
124
125## Mining Payout Modes
126
127### `auto` (default)
128```
129TollGate boots → connects to WiFi (STA)
130 → tollgate_client_detect(gw_ip)
131 → GET http://gw_ip:2121/
132 → If upstream TollGate detected → mine to upstream proxy → earn e-cash/bytes
133 → If regular router → mine to Braiins pool → earn Lightning sats
134```
135
136### `pool`
137Always mine to Braiins/public-pool via SV2. Never mine to upstream TollGate. Gateway's own hashrate earns Lightning sats for the operator.
138
139### `upstream`
140Always mine to upstream TollGate's proxy. Fail if no upstream TollGate detected. Gateway's own hashrate earns e-cash/bytes/minutes.
141
142### `proxy_only`
143Don't mine locally at all. Only run the local proxy for downstream miners. Useful for plain ESP32 relay nodes without ASICs that don't want to waste CPU on mining.
144
145## Sandbox / Firewall Changes
146
147Unauthenticated clients (no Cashu, no session) get access to:
148- `TCP :3333` — mining proxy (get jobs, submit shares)
149- `TCP :2121` — tollgate API (`GET /mining/job`, `POST /mining/share`)
150- `TCP :80` — captive portal
151- `TCP/443` to `mint_url` — so miners can receive e-cash from mobile wallets
152
153## Hashrate-to-Bandwidth Conversion
154
155```
156difficulty = nbits_to_difficulty(job.nbits)
157hashprice_sats_per_ghs_day = (312500000 * 144) / (difficulty * 2^32)
158hashprice_sats_per_ghs_s = hashprice_sats_per_ghs_day / 86400
159
160allotment_ms = (client_hashrate_ghs * hashprice_sats_per_ghs_s * measurement_window_s)
161 / price_per_step * step_size_ms
162```
163
164The measurement window is a sliding interval (e.g., 30 seconds). Shares submitted during the window are counted, hashrate is estimated, and allotment is calculated and granted via `session_create()` or `session_extend()`.
165
166## New Files
167
168| File | Purpose |
169|------|---------|
170| `main/stratum_client.c/h` | SV2 upstream client (connect to Braiins, Noise handshake, receive jobs, submit shares) |
171| `main/stratum_proxy.c/h` | Local SV1 TCP server on :3333 (distribute jobs, collect shares, per-IP hashrate meter) |
172| `main/mining_payment.c/h` | Share validation (SHA256d check), hashprice calculation, session creation |
173| `main/sw_miner.c/h` | Software SHA256 miner using ESP32-S3 hardware SHA256 accelerator |
174| `main/asic_miner.c/h` | BM1366/BM1368 ASIC detection + driver wrapper |
175| `tests/unit/test_mining_payment.c` | Hashprice calculation tests, share validation tests |
176| `tests/unit/test_stratum_proxy.c` | SV1/SV2 frame parsing tests |
177
178## Modified Files
179
180| File | Changes |
181|------|---------|
182| `main/tollgate_api.c` | Add `GET /mining/job`, `POST /mining/share`; add mining tag to `GET /` discovery |
183| `main/tollgate_client.c` | Add mining mode (detect upstream mining support, mine instead of Cashu) |
184| `main/tollgate_client.h` | New states: `TG_CLIENT_MINING`, `TG_CLIENT_MINING_ACTIVE` |
185| `main/firewall.c/h` | Quarantine allowlist: mining port + mint URLs for unauthenticated clients |
186| `main/dns_server.c/h` | Resolve mint URLs for unauthenticated clients |
187| `main/session.c/h` | Add `payment_method` field (Cashu vs mining) |
188| `main/config.c/h` | Parse all new mining config fields |
189| `main/captive_portal.c` | "Mine for Access" tab in portal HTML |
190| `main/tollgate_main.c` | Start mining tasks, init ASIC detection |
191| `CMakeLists.txt` | Add new source files, reference BitAxe submodule |
192| `.gitmodules` | Add `bitaxeorg/ESP-Miner` submodule |
193
194## Implementation Phases
195
196### Phase 1: Foundation (config + submodule + build)
197- [ ] Add `bitaxeorg/ESP-Miner` as git submodule at `components/esp-miner/`
198- [ ] Add mining config fields to `config.c/h`
199- [ ] Update `CMakeLists.txt` to compile new sources
200- [ ] Verify build compiles cleanly
201
202### Phase 2: Stratum client (SV2 upstream)
203- [ ] Create `main/stratum_client.c/h`
204- [ ] SV2 connection lifecycle: TCP connect → Noise handshake → SetupConnection → OpenChannel → receive jobs
205- [ ] Job reception: parse NewMiningJob, SetNewPrevHash, SetTarget
206- [ ] Share submission: forward shares from local proxy to upstream pool
207- [ ] Fallback: if SV2 fails, try SV1 to public-pool.io
208
209### Phase 3: Stratum proxy (local SV1 server)
210- [ ] Create `main/stratum_proxy.c/h`
211- [ ] TCP listener on `:3333`
212- [ ] SV1 JSON-RPC: `mining.subscribe`, `mining.authorize`, `mining.notify`, `mining.submit`
213- [ ] Distribute current job to connected miners
214- [ ] Collect shares, forward to stratum_client for upstream submission
215- [ ] Per-client IP hashrate meter (shares / time window)
216
217### Phase 4: Mining payment
218- [ ] Create `main/mining_payment.c/h`
219- [ ] `nbits_to_difficulty()` conversion
220- [ ] `calculate_hashprice()` from difficulty + block subsidy
221- [ ] `validate_share()` — SHA256d(header) < target check
222- [ ] `shares_to_allotment()` — hashrate → bandwidth conversion
223- [ ] Integration with `session_create()` / `session_extend()`
224
225### Phase 5: API endpoints
226- [ ] `GET /mining/job` — return current block template as JSON
227- [ ] `POST /mining/share` — accept share, validate, create/extend session
228- [ ] Add mining tag to `GET /` discovery response
229- [ ] `GET /mining/stats` — current hashrate, total shares, hashprice
230
231### Phase 6: Firewall sandbox
232- [ ] `firewall.c` — quarantine allowlist for `:3333`, `:2121`, `:80`
233- [ ] `firewall.c` — conditional allow mint URL hostnames if `mining_sandbox_mint_access`
234- [ ] `dns_server.c` — resolve mint URLs for unauthenticated clients
235
236### Phase 7: Client mining mode
237- [ ] `tollgate_client.c` — detect upstream mining support via discovery tag
238- [ ] New state machine: `TG_CLIENT_MINING` → `TG_CLIENT_MINING_ACTIVE`
239- [ ] Connect to upstream `:3333` mining proxy
240- [ ] Submit shares to earn bandwidth
241
242### Phase 8: Software miner
243- [ ] Create `main/sw_miner.c/h`
244- [ ] ESP32-S3 hardware SHA256 accelerator via `esp_sha.h` / mbedtls
245- [ ] Get job from local stratum proxy, iterate nonces, check against target
246- [ ] Low-priority FreeRTOS task (don't starve WiFi/routing)
247- [ ] Expected: ~10-50 kH/s
248
249### Phase 9: ASIC miner
250- [ ] Create `main/asic_miner.c/h`
251- [ ] Probe SPI bus at boot for BM1366/BM1368
252- [ ] If ASIC found: use BitAxe driver (`BM1366_send_work`, `BM1366_process_work`)
253- [ ] If no ASIC: fall back to software miner
254- [ ] Expected: ~500 GH/s (BM1366) or ~120 GH/s (BM1368)
255
256### Phase 10: Portal UI
257- [ ] Add "Mine for Access" tab to captive portal HTML
258- [ ] Show current hashrate, shares submitted, time earned
259- [ ] Auto-start mining when tab is opened (JavaScript Web Crypto SHA256 in browser)
260- [ ] Show progress bar / earnings counter
261
262### Phase 11: CVM integration
263- [ ] Add `get_hashprice` MCP tool to `mcp_handler.c/h`
264- [ ] Returns current hashprice, difficulty, estimated earnings
265- [ ] `set_mining_config` tool for remote configuration
266
267### Phase 12: Main integration
268- [ ] `tollgate_main.c` — start stratum_client task on boot
269- [ ] `tollgate_main.c` — start stratum_proxy task on boot
270- [ ] `tollgate_main.c` — start sw_miner task on boot
271- [ ] `tollgate_main.c` — start asic_miner task if ASIC detected
272- [ ] Mining task lifecycle: start/stop with services
273
274### Phase 13: Tests
275- [ ] Unit test: `test_mining_payment.c` — hashprice calc, nbits→difficulty, share validation
276- [ ] Unit test: `test_stratum_proxy.c` — SV1 frame parsing, SV2 frame encode/decode
277- [ ] Integration test: `mining.mjs` — submit share, verify session, check bandwidth
278- [ ] E2E test: `mining.spec.mjs` — portal mining tab, hashrate display
279
280## Checklist — Implementation Progress
281
282### Phase 1: Foundation
283- [ ] Add BitAxe git submodule
284- [ ] Mining config fields in config.c/h
285- [ ] CMakeLists.txt updated
286- [ ] Clean build verified
287
288### Phase 2: Stratum Client
289- [ ] stratum_client.c/h created
290- [ ] SV2 Noise handshake
291- [ ] Job reception
292- [ ] Share submission
293- [ ] SV1 fallback
294
295### Phase 3: Stratum Proxy
296- [ ] stratum_proxy.c/h created
297- [ ] SV1 JSON-RPC server
298- [ ] Job distribution
299- [ ] Share collection
300- [ ] Per-IP hashrate meter
301
302### Phase 4: Mining Payment
303- [ ] mining_payment.c/h created
304- [ ] nbits_to_difficulty
305- [ ] hashprice calculation
306- [ ] share validation (SHA256d)
307- [ ] shares_to_allotment conversion
308- [ ] session_create integration
309
310### Phase 5: API Endpoints
311- [ ] GET /mining/job
312- [ ] POST /mining/share
313- [ ] Mining discovery tag
314- [ ] GET /mining/stats
315
316### Phase 6: Firewall Sandbox
317- [ ] Quarantine allowlist for mining ports
318- [ ] Mint URL access for unauthenticated clients
319- [ ] DNS resolution in sandbox
320
321### Phase 7: Client Mining Mode
322- [ ] Mining support detection in tollgate_client.c
323- [ ] TG_CLIENT_MINING states
324- [ ] Upstream proxy connection
325- [ ] Share submission for bandwidth
326
327### Phase 8: Software Miner
328- [ ] sw_miner.c/h created
329- [ ] ESP32-S3 HW SHA256
330- [ ] Job dequeue → nonce iteration → target check
331- [ ] Low-priority task
332
333### Phase 9: ASIC Miner
334- [ ] asic_miner.c/h created
335- [ ] BM1366/BM1368 SPI detection
336- [ ] ASIC mining loop
337- [ ] Software fallback
338
339### Phase 10: Portal UI
340- [ ] "Mine for Access" tab
341- [ ] Hashrate display
342- [ ] Earnings counter
343
344### Phase 11: CVM Integration
345- [ ] get_hashprice MCP tool
346- [ ] set_mining_config MCP tool
347
348### Phase 12: Main Integration
349- [ ] Mining tasks started on boot
350- [ ] ASIC detection at boot
351- [ ] Task lifecycle management
352
353### Phase 13: Tests
354- [ ] test_mining_payment.c
355- [ ] test_stratum_proxy.c
356- [ ] integration/mining.mjs
357- [ ] e2e/mining.spec.mjs