diff options
| -rw-r--r-- | MINER_INTEGRATION_PLAN.md | 177 | ||||
| -rw-r--r-- | components/negentropy_lib/CMakeLists.txt | 20 | ||||
| -rw-r--r-- | components/negentropy_lib/compat/openssl/sha.h | 16 | ||||
| -rw-r--r-- | main/CMakeLists.txt | 11 | ||||
| -rw-r--r-- | main/config.c | 20 | ||||
| -rw-r--r-- | main/tollgate_api.c | 1 |
6 files changed, 218 insertions, 27 deletions
diff --git a/MINER_INTEGRATION_PLAN.md b/MINER_INTEGRATION_PLAN.md new file mode 100644 index 0000000..7b4554d --- /dev/null +++ b/MINER_INTEGRATION_PLAN.md | |||
| @@ -0,0 +1,177 @@ | |||
| 1 | # Miner Integration Plan | ||
| 2 | |||
| 3 | ## Goal | ||
| 4 | |||
| 5 | Integrate TollGate paid-WiFi with Bitcoin mining hardware (BitAxe/NerdAxe family) so that | ||
| 6 | miners earn internet access by mining real Bitcoin blocks via Stratum v1. Uses the | ||
| 7 | `tollgate_core` ESP-IDF component consumed by NerdQAxePlus via the IDF Component Manager. | ||
| 8 | |||
| 9 | ## Hardware Targets | ||
| 10 | |||
| 11 | | Device | Board | ASIC | Chips | Build Flag | Status | | ||
| 12 | |--------|-------|------|-------|------------|--------| | ||
| 13 | | NerdAxe Ultra 500GH/s | `NERDAXE` | BM1366 | 1 | `BOARD=NERDAXE TOLLGATE=1` | Available for testing | | ||
| 14 | | NerdQAxe++ Hydro 4.8TH/s | `NERDQAXEPLUS2` | BM1370 | 4 | `BOARD=NERDQAXEPLUS2 TOLLGATE=1` | Future | | ||
| 15 | | BitAxe Gamma 601 1.5TH/s | `GAMMA` | BM1366 | 1 | Upstream BitAxe | Future reference | | ||
| 16 | |||
| 17 | ## Architecture | ||
| 18 | |||
| 19 | ``` | ||
| 20 | esp32-tollgate (this repo) | ||
| 21 | components/tollgate_core/ ← shared ESP-IDF component | ||
| 22 | CMakeLists.txt | ||
| 23 | idf_component.yml | ||
| 24 | include/ | ||
| 25 | tollgate_core.h ← public API | ||
| 26 | tollgate_platform.h ← platform interface (callbacks) | ||
| 27 | src/ | ||
| 28 | tollgate_core_cashu.c/h ← from main/cashu.c | ||
| 29 | tollgate_core_dns.c/h ← from main/dns_server.c | ||
| 30 | tollgate_core_firewall.c/h ← from main/firewall.c | ||
| 31 | tollgate_core_session.c/h ← from main/session.c | ||
| 32 | tollgate_core_mining.c/h ← from main/mining_payment.c | ||
| 33 | tollgate_core_stratum_proxy.c/h ← from main/stratum_proxy.c | ||
| 34 | main/ | ||
| 35 | tollgate_platform.c ← standalone impl (SPIFFS config) | ||
| 36 | ... ← rest of standalone firmware | ||
| 37 | |||
| 38 | ESP-Miner-NerdQAxePlus (fork of shufps/ESP-Miner-NerdQAxePlus) | ||
| 39 | main/idf_component.yml ← declares tollgate_core dependency | ||
| 40 | main/tollgate_platform.cpp ← implements platform interface (NVS config + ASIC state) | ||
| 41 | main/boards/tollgate_board.h/cpp ← TollGateBoard extends NerdAxe | ||
| 42 | main/tasks/asic_result_task.cpp ← 3-line #ifdef TOLLGATE hook | ||
| 43 | main/main.cpp ← #ifdef TOLLGATE init block | ||
| 44 | ``` | ||
| 45 | |||
| 46 | ## Key Design Decisions | ||
| 47 | |||
| 48 | | Decision | Choice | Rationale | | ||
| 49 | |----------|--------|-----------| | ||
| 50 | | ESP-Miner fork | NerdQAxePlus (shufps) | C++17 OOP, 9 board types, V1+V2, most maintained (877 stars) | | ||
| 51 | | Component distribution | IDF Component Manager | Clean API boundary, automatic transitive deps | | ||
| 52 | | Mining in tollgate_core | Extend existing component | Same payment core, mining hooks via platform interface | | ||
| 53 | | Component reconciliation | Cherry-pick skeleton from arch branch | Keep arch's proven interface design, fill with current master code | | ||
| 54 | | nucula wallet | Git submodule (unchanged) | Cherry-picks source files — Component Manager can't do this | | ||
| 55 | |||
| 56 | ## Plan Checklist | ||
| 57 | |||
| 58 | ### Step 1: Fix Master Build — COMPLETE | ||
| 59 | |||
| 60 | - [x] Create `components/negentropy/CMakeLists.txt` (register C++ wrapper as ESP-IDF component) | ||
| 61 | - [x] Fix `main/CMakeLists.txt` (remove `esp_littlefs`, `esp_timer`, `tcp_transport` from REQUIRES) | ||
| 62 | - [x] `idf.py build` passes on master | ||
| 63 | - [x] `make test-unit` passes (19 test suites, 344+ assertions) | ||
| 64 | - [x] Commit + push | ||
| 65 | |||
| 66 | ### Step 2: Create Miner Integration Branch + Worktree | ||
| 67 | |||
| 68 | - [ ] Create `feature/miner-integration` branch from master | ||
| 69 | - [ ] Create git worktree at `/home/c03rad0r/esp32-miner-integration` | ||
| 70 | - [ ] Verify worktree builds and tests pass (same as master) | ||
| 71 | |||
| 72 | ### Step 3: Cherry-pick tollgate_core Skeleton from Arch Branch | ||
| 73 | |||
| 74 | - [ ] Copy `components/tollgate_core/CMakeLists.txt` from `feature/tollgate-core-component` | ||
| 75 | - [ ] Copy `components/tollgate_core/idf_component.yml` from `feature/tollgate-core-component` | ||
| 76 | - [ ] Copy `components/tollgate_core/include/tollgate_core.h` from `feature/tollgate-core-component` | ||
| 77 | - [ ] Copy `components/tollgate_core/include/tollgate_platform.h` from `feature/tollgate-core-component` | ||
| 78 | - [ ] Extend `tollgate_platform.h` with mining callbacks (get_stratum_url, on_share_accepted, etc.) | ||
| 79 | - [ ] Extend `tollgate_core.h` with mining API (tollgate_core_start_stratum_proxy, etc.) | ||
| 80 | |||
| 81 | ### Step 4: Populate tollgate_core with Current Master Modules | ||
| 82 | |||
| 83 | - [ ] Copy + rename `main/cashu.c` → `components/tollgate_core/src/tollgate_core_cashu.c` | ||
| 84 | - [ ] Copy + rename `main/dns_server.c` → `components/tollgate_core/src/tollgate_core_dns.c` | ||
| 85 | - [ ] Copy + rename `main/firewall.c` → `components/tollgate_core/src/tollgate_core_firewall.c` | ||
| 86 | - [ ] Copy + rename `main/session.c` → `components/tollgate_core/src/tollgate_core_session.c` | ||
| 87 | - [ ] Copy + rename `main/mining_payment.c` → `components/tollgate_core/src/tollgate_core_mining.c` | ||
| 88 | - [ ] Copy + rename `main/stratum_proxy.c` → `components/tollgate_core/src/tollgate_core_stratum_proxy.c` | ||
| 89 | - [ ] Implement `tollgate_core.c` — wire all sub-modules via platform callbacks | ||
| 90 | - [ ] Update `components/tollgate_core/CMakeLists.txt` with all SRCS and REQUIRES | ||
| 91 | |||
| 92 | ### Step 5: Wire tollgate_core into Standalone Build | ||
| 93 | |||
| 94 | - [ ] Create `main/tollgate_platform.c` implementing platform interface (SPIFFS config) | ||
| 95 | - [ ] Update `main/CMakeLists.txt` — remove old SRCS, add tollgate_core to REQUIRES | ||
| 96 | - [ ] Update `main/tollgate_main.c` — call `tollgate_core_init()` instead of direct module calls | ||
| 97 | - [ ] Update `main/tollgate_api.c` — call `tollgate_core_*` API | ||
| 98 | - [ ] Update `main/lwip_tollgate_hooks.h` — call `tollgate_core_is_client_allowed()` | ||
| 99 | - [ ] `idf.py build` passes standalone | ||
| 100 | - [ ] `make test-unit` passes | ||
| 101 | - [ ] Flash to Board A + smoke test | ||
| 102 | - [ ] Commit | ||
| 103 | |||
| 104 | ### Step 6: Fork NerdQAxePlus + Set Up Build | ||
| 105 | |||
| 106 | - [ ] Fork `shufps/ESP-Miner-NerdQAxePlus` on GitHub | ||
| 107 | - [ ] Clone fork to `/home/c03rad0r/esp-miner-nerdqaxeplus/` | ||
| 108 | - [ ] Verify stock build: `BOARD=NERDAXE idf.py build` | ||
| 109 | - [ ] Add `main/idf_component.yml` declaring tollgate_core dependency | ||
| 110 | - [ ] Verify Component Manager resolves tollgate_core | ||
| 111 | |||
| 112 | ### Step 7: Implement NerdQAxePlus TollGate Integration | ||
| 113 | |||
| 114 | - [ ] Create `main/tollgate_platform.cpp` — implements platform interface with NVS config + ASIC state | ||
| 115 | - [ ] Create `main/boards/tollgate_board.h/cpp` — TollGateBoard extends NerdAxe (AP+STA WiFi) | ||
| 116 | - [ ] Patch `main/tasks/asic_result_task.cpp` — `#ifdef TOLLGATE` hook on share accepted | ||
| 117 | - [ ] Patch `main/main.cpp` — `#ifdef TOLLGATE` init block (AP, DNS, captive portal, stratum proxy) | ||
| 118 | - [ ] Create `main/lwip_tollgate_hooks.h` — LWIP hook forwarding to tollgate_core | ||
| 119 | - [ ] Update `main/CMakeLists.txt` — conditional TOLLGATE sources | ||
| 120 | - [ ] Update top-level `CMakeLists.txt` — `-DTOLLGATE` compile definition when env var set | ||
| 121 | - [ ] Build: `BOARD=NERDAXE TOLLGATE=1 idf.py build` | ||
| 122 | |||
| 123 | ### Step 8: Hardware Testing on NerdAxe Ultra | ||
| 124 | |||
| 125 | - [ ] Flash stock NerdQAxePlus (no TollGate) — verify mining works (regression) | ||
| 126 | - [ ] Flash with `TOLLGATE=1` — verify: | ||
| 127 | - [ ] Stock mining still works (hashrate normal) | ||
| 128 | - [ ] WiFi AP starts with TollGate SSID | ||
| 129 | - [ ] Captive portal serves payment page | ||
| 130 | - [ ] DNS hijack/forward works (pre/post auth) | ||
| 131 | - [ ] Local stratum proxy on port 3334 accepts downstream miners | ||
| 132 | - [ ] Shares from downstream miners count toward internet access | ||
| 133 | - [ ] Captive portal mining tab shows hashrate + time earned | ||
| 134 | - [ ] LVGL display shows TollGate session info alongside mining stats | ||
| 135 | - [ ] Write integration tests | ||
| 136 | - [ ] Commit + push | ||
| 137 | |||
| 138 | ### Step 9: Cleanup + Documentation | ||
| 139 | |||
| 140 | - [ ] Remove old `main/cashu.c`, `main/dns_server.c`, `main/firewall.c`, `main/session.c` from standalone (replaced by component) | ||
| 141 | - [ ] Update AGENTS.md with miner integration docs | ||
| 142 | - [ ] Update PLAN.md | ||
| 143 | - [ ] Squash-merge `feature/miner-integration` into master | ||
| 144 | - [ ] Remove worktree | ||
| 145 | |||
| 146 | ## Open Questions | ||
| 147 | |||
| 148 | - [ ] Does the IDF Component Manager initialize git submodules within git-sourced deps? (nucula_src) | ||
| 149 | - [ ] Should tollgate_core publish to ESP Component Registry or stay git-only? | ||
| 150 | - [ ] Versioning scheme for tollgate_core? (semver tags in esp32-tollgate?) | ||
| 151 | - [ ] Display theme: new LVGL screen in NerdQAxePlus, or overlay on existing mining screen? | ||
| 152 | |||
| 153 | ## Relevant Files | ||
| 154 | |||
| 155 | ### Master (esp32-tollgate) | ||
| 156 | - `main/CMakeLists.txt` — build config (needs negentropy fix) | ||
| 157 | - `components/negentropy/` — NIP-77 set reconciliation (needs CMakeLists.txt) | ||
| 158 | - `main/mining_payment.c/h` — hashprice, share validation | ||
| 159 | - `main/stratum_proxy.c/h` — local SV1 TCP server | ||
| 160 | - `main/stratum_client.c/h` — upstream pool connection | ||
| 161 | - `main/sw_miner.c/h` — software SHA256d miner | ||
| 162 | - `main/asic_miner.c/h` — ASIC detection stub | ||
| 163 | |||
| 164 | ### Arch Branch (feature/tollgate-core-component) | ||
| 165 | - `components/tollgate_core/CMakeLists.txt` — component registration | ||
| 166 | - `components/tollgate_core/idf_component.yml` — Component Manager metadata | ||
| 167 | - `components/tollgate_core/include/tollgate_core.h` — public API | ||
| 168 | - `components/tollgate_core/include/tollgate_platform.h` — platform interface | ||
| 169 | - `docs/TOLLGATE_CORE_DESIGN.md` — architecture decision record | ||
| 170 | |||
| 171 | ### NerdQAxePlus (shufps/ESP-Miner-NerdQAxePlus) | ||
| 172 | - `main/boards/nerdaxe.cpp` — NerdAxe Ultra board definition (BM1366) | ||
| 173 | - `main/boards/nerdqaxeplus2.cpp` — NerdQAxe++ Hydro board definition (BM1370) | ||
| 174 | - `main/tasks/asic_result_task.cpp` — share acceptance hook point | ||
| 175 | - `main/stratum/stratum_manager.h` — Stratum V1+V2 abstraction | ||
| 176 | - `main/displays/displayDriver.cpp` — LVGL ST7789 TFT display | ||
| 177 | - `main/main.cpp` — entry point with BOARD selection | ||
diff --git a/components/negentropy_lib/CMakeLists.txt b/components/negentropy_lib/CMakeLists.txt new file mode 100644 index 0000000..32bab60 --- /dev/null +++ b/components/negentropy_lib/CMakeLists.txt | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | set(NEGENTROPY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../negentropy) | ||
| 2 | |||
| 3 | idf_component_register( | ||
| 4 | SRCS "${NEGENTROPY_DIR}/c/negentropy_wrapper.cpp" | ||
| 5 | INCLUDE_DIRS | ||
| 6 | "${NEGENTROPY_DIR}/c" | ||
| 7 | "${NEGENTROPY_DIR}/cpp" | ||
| 8 | "compat" | ||
| 9 | REQUIRES mbedtls | ||
| 10 | ) | ||
| 11 | |||
| 12 | target_compile_options(${COMPONENT_LIB} PRIVATE | ||
| 13 | -fexceptions | ||
| 14 | -frtti | ||
| 15 | -Wno-error | ||
| 16 | -Wno-delete-non-virtual-dtor | ||
| 17 | -Wno-unused-variable | ||
| 18 | -Wno-unused-function | ||
| 19 | -Wno-catch-value | ||
| 20 | ) | ||
diff --git a/components/negentropy_lib/compat/openssl/sha.h b/components/negentropy_lib/compat/openssl/sha.h new file mode 100644 index 0000000..b0881c1 --- /dev/null +++ b/components/negentropy_lib/compat/openssl/sha.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | #ifndef OPENSSL_SHA_COMPAT_H | ||
| 2 | #define OPENSSL_SHA_COMPAT_H | ||
| 3 | |||
| 4 | #include "mbedtls/sha256.h" | ||
| 5 | #include <stddef.h> | ||
| 6 | |||
| 7 | #define SHA256_DIGEST_LENGTH 32 | ||
| 8 | |||
| 9 | static inline int SHA256_compat(const unsigned char *d, size_t n, unsigned char *md) | ||
| 10 | { | ||
| 11 | return mbedtls_sha256(d, n, md, 0); | ||
| 12 | } | ||
| 13 | |||
| 14 | #define SHA256 SHA256_compat | ||
| 15 | |||
| 16 | #endif | ||
diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 0669b70..90000b7 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt | |||
| @@ -31,9 +31,8 @@ idf_component_register(SRCS "tollgate_main.c" | |||
| 31 | "sw_miner.c" | 31 | "sw_miner.c" |
| 32 | "asic_miner.c" | 32 | "asic_miner.c" |
| 33 | INCLUDE_DIRS "." | 33 | INCLUDE_DIRS "." |
| 34 | REQUIRES esp_wifi esp_event esp_netif nvs_flash esp_http_server | 34 | REQUIRES esp_wifi esp_event esp_netif nvs_flash esp_http_server |
| 35 | lwip json esp_http_client mbedtls esp-tls log spiffs | 35 | lwip json esp_http_client mbedtls esp-tls log spiffs |
| 36 | nucula_lib secp256k1 axs15231b qrcode wisp_relay | 36 | nucula_lib secp256k1 axs15231b qrcode wisp_relay |
| 37 | esp_littlefs negentropy | 37 | negentropy_lib tcp_transport |
| 38 | esp_timer tcp_transport | 38 | PRIV_REQUIRES esp-tls) |
| 39 | PRIV_REQUIRES esp-tls) | ||
diff --git a/main/config.c b/main/config.c index 6644b3a..aa7da6d 100644 --- a/main/config.c +++ b/main/config.c | |||
| @@ -321,26 +321,6 @@ esp_err_t tollgate_config_init(void) | |||
| 321 | g_config.payout.mint_count = 1; | 321 | g_config.payout.mint_count = 1; |
| 322 | } | 322 | } |
| 323 | 323 | ||
| 324 | cJSON *seed_relays = cJSON_GetObjectItem(root, "nostr_seed_relays"); | ||
| 325 | if (seed_relays && cJSON_IsArray(seed_relays)) { | ||
| 326 | int srcount = cJSON_GetArraySize(seed_relays); | ||
| 327 | if (srcount > TOLLGATE_MAX_SEED_RELAYS) srcount = TOLLGATE_MAX_SEED_RELAYS; | ||
| 328 | for (int i = 0; i < srcount; i++) { | ||
| 329 | cJSON *r = cJSON_GetArrayItem(seed_relays, i); | ||
| 330 | if (r && cJSON_IsString(r)) { | ||
| 331 | strncpy(g_config.nostr_seed_relays[i], r->valuestring, | ||
| 332 | sizeof(g_config.nostr_seed_relays[i]) - 1); | ||
| 333 | g_config.nostr_seed_relay_count++; | ||
| 334 | } | ||
| 335 | } | ||
| 336 | } | ||
| 337 | |||
| 338 | cJSON *sync_interval = cJSON_GetObjectItem(root, "nostr_sync_interval_s"); | ||
| 339 | if (sync_interval) g_config.nostr_sync_interval_s = sync_interval->valueint; | ||
| 340 | |||
| 341 | cJSON *fallback_interval = cJSON_GetObjectItem(root, "nostr_fallback_sync_interval_s"); | ||
| 342 | if (fallback_interval) g_config.nostr_fallback_sync_interval_s = fallback_interval->valueint; | ||
| 343 | |||
| 344 | cJSON *mining = cJSON_GetObjectItem(root, "mining"); | 324 | cJSON *mining = cJSON_GetObjectItem(root, "mining"); |
| 345 | if (mining && cJSON_IsObject(mining)) { | 325 | if (mining && cJSON_IsObject(mining)) { |
| 346 | cJSON *m_en = cJSON_GetObjectItem(mining, "enabled"); | 326 | cJSON *m_en = cJSON_GetObjectItem(mining, "enabled"); |
diff --git a/main/tollgate_api.c b/main/tollgate_api.c index b775f55..45cd02f 100644 --- a/main/tollgate_api.c +++ b/main/tollgate_api.c | |||
| @@ -678,7 +678,6 @@ static esp_err_t api_get_mining_stats(httpd_req_t *req) | |||
| 678 | httpd_resp_send(req, json, strlen(json)); | 678 | httpd_resp_send(req, json, strlen(json)); |
| 679 | cJSON_free(json); | 679 | cJSON_free(json); |
| 680 | cJSON_Delete(root); | 680 | cJSON_Delete(root); |
| 681 | >>>>>>> feature/mining-payment | ||
| 682 | return ESP_OK; | 681 | return ESP_OK; |
| 683 | } | 682 | } |
| 684 | 683 | ||