From 10c69b0ddc34a1fafada3f8b68a622b4aa2bea77 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 23 May 2026 02:18:41 +0530 Subject: chore: fix unit test build rules, add relay_selector+relay_validator tests, persist core extraction plan --- PLAN_TOLLGATE_CORE_EXTRACTION.md | 281 +++++++++++++++++++++++++++++++++ tests/unit/Makefile | 8 +- tests/unit/stubs/freertos/FreeRTOS.h | 1 + tests/unit/test_beacon_price | Bin 35744 -> 0 bytes tests/unit/test_display | Bin 24816 -> 0 bytes tests/unit/test_firewall_sandbox | Bin 30568 -> 0 bytes tests/unit/test_market | Bin 49456 -> 0 bytes tests/unit/test_mining_payment | Bin 28664 -> 0 bytes tests/unit/test_negentropy_adapter | Bin 21216 -> 0 bytes tests/unit/test_session_payment_method | Bin 54680 -> 0 bytes tests/unit/test_stratum_proxy | Bin 40784 -> 0 bytes tests/unit/test_tollgate_client_mining | Bin 48448 -> 0 bytes 12 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 PLAN_TOLLGATE_CORE_EXTRACTION.md delete mode 100755 tests/unit/test_beacon_price delete mode 100755 tests/unit/test_display delete mode 100755 tests/unit/test_firewall_sandbox delete mode 100755 tests/unit/test_market delete mode 100755 tests/unit/test_mining_payment delete mode 100755 tests/unit/test_negentropy_adapter delete mode 100755 tests/unit/test_session_payment_method delete mode 100755 tests/unit/test_stratum_proxy delete mode 100755 tests/unit/test_tollgate_client_mining diff --git a/PLAN_TOLLGATE_CORE_EXTRACTION.md b/PLAN_TOLLGATE_CORE_EXTRACTION.md new file mode 100644 index 0000000..28b9ac3 --- /dev/null +++ b/PLAN_TOLLGATE_CORE_EXTRACTION.md @@ -0,0 +1,281 @@ +# TollGate Core Extraction Plan + +## Goal + +Extract TollGate business logic into a **reusable standalone C library** (`tollgate_core/`) wrapped by a **thin ESP-IDF component** (`components/tollgate_esp/`), so that: + +- **BitAxe/NerdQAxePlus** gets: full captive portal + Stratum V1 mining + eCash payment + session management +- **ESP32-TollGate** gets: all of the above + Nostr identity + relay + CVM + display +- **Desktop/CI** gets: pure logic tests with no ESP-IDF stubs needed + +--- + +## Architecture Overview + +``` +┌─────────────────────────────────────────────────────────┐ +│ Consumer Application (main/) │ +│ esp32-tollgate: tollgate_main.c, tollgate_api.c, etc. │ +│ esp-miner: main.cpp, asic_result_task.cpp │ +└────────────────────┬────────────────────────────────────┘ + │ + ┌────────────┴─────────────┐ + │ components/tollgate_esp │ ← ESP-IDF component wrapper + │ (implements platform_t │ via idf_component.yml + │ using ESP-IDF APIs) │ + └────────────┬────────────┘ + │ + ┌────────────────┴────────────────┐ + │ tollgate_core/ │ ← Standalone C library + │ (zero ESP-IDF deps) │ + │ │ + │ Layer 0: Pure Logic │ + │ cashu_decode, allotment, │ + │ session state machine, │ + │ mining_payment economics │ + │ │ + │ Layer 1: Protocol Logic │ + │ DNS parser + server logic, │ + │ Stratum V1 protocol, │ + │ beacon IE builder/parser │ + │ │ + │ Layer 2: Platform-dependent │ + │ (via tollgate_platform.h) │ + │ HTTP client, task creation, │ + │ socket I/O, time source, │ + │ logging, wallet operations │ + └─────────────────────────────────┘ +``` + +## Module Classification + +| Module | Layer | Goes into tollgate_core? | Notes | +|--------|-------|--------------------------|-------| +| `cashu.c` — token decode, allotment math | 0 | **Yes** | Pure C + cJSON + mbedtls base64/sha256 | +| `session.c` — lifecycle, expiry, extend | 0 | **Yes** | Pure state machine, time via callback | +| `mining_payment.c` — hashprice, allotment | 0 | **Yes** | Pure math (nbits→difficulty→hashprice→allotment) | +| `dns_server.c` — DNS protocol, per-client auth | 1 | **Yes** | Protocol parser pure; socket IO via platform | +| `stratum_proxy.c` — SV1 TCP server | 1 | **Yes** | JSON protocol pure; TCP via platform | +| `stratum_client.c` — SV1 pool client | 1 | **Yes** | JSON protocol pure; TCP via platform | +| `beacon_price.c` — WiFi IE builder/parser | 1 | **Yes** | IE struct packing pure; esp_wifi_set_vendor_ie via platform | +| `market.c` — IE scanner, cheapest finder | 1 | **Yes** | IE parser + price comparison pure; scan results via platform | +| `firewall.c` — client allowlist, NAT filter | 2 | **Yes** | Allowlist logic pure; lwIP hook + MAC resolve via platform | +| `config.c` — JSON config parsing | — | **No** | Stays in consumer. Core takes config via `platform_t` | +| `identity.c` — HMAC derivation from nsec | — | **No** | Nostr-specific, stays in esp32-tollgate | +| `nostr_event.c` — Schnorr signing | — | **No** | Nostr-specific | +| `wifistr.c` — kind 38787 events | — | **No** | Nostr-specific | +| `cvm_server.c` — MCP over Nostr | — | **No** | Nostr-specific | +| `relay_selector.c` — NIP-11 probing | — | **No** | Nostr-specific | +| `sync_manager.c` — REQ-diff sync | — | **No** | Nostr-specific | +| `local_relay.c` — NIP-01 server | — | **No** | Nostr-specific | +| `display.c` — TFT rendering | — | **No** | Hardware-specific | +| `tollgate_client.c` — downstream auto-pay | — | **No** | Consumes core API, but isn't core itself | +| `nucula_lib` — wallet C++ impl | — | **No** | External dep; core uses wallet via platform callback | +| `mint_health.c` — health probe + wallet queue | — | **Partial** | Health state machine extractable; wallet queue stays in consumer | + +## Platform Interface (`tollgate_platform.h`) + +```c +typedef struct { + // --- Config access --- + uint16_t (*get_price_sats)(void); + int32_t (*get_step_ms)(void); + int64_t (*get_step_bytes)(void); + const char* (*get_mint_url)(void); + const char* (*get_metric)(void); + + // --- Time --- + int64_t (*get_time_ms)(void); + + // --- Logging --- + void (*log_info)(const char *tag, const char *fmt, ...); + void (*log_warn)(const char *tag, const char *fmt, ...); + void (*log_error)(const char *tag, const char *fmt, ...); + + // --- Wallet (can be NULL — accepts payment without spending) --- + bool (*wallet_receive)(const char *token); + bool (*wallet_send)(uint64_t amount, char *buf, size_t buf_len); + uint64_t (*wallet_balance)(void); + + // --- HTTP client (for checkstate) --- + int (*http_post)(const char *url, const char *headers, + const char *body, int body_len, + char *resp, int resp_len); + + // --- Task/thread creation --- + bool (*create_task)(void (*fn)(void*), void *arg, + const char *name, int stack_bytes, int priority); + + // --- Socket I/O (for DNS + Stratum) --- + int (*socket_udp)(void); + int (*socket_tcp)(void); + int (*socket_bind)(int fd, uint32_t ip, uint16_t port); + int (*socket_listen)(int fd, int backlog); + int (*socket_accept)(int fd, uint32_t *client_ip, uint16_t *client_port); + int (*socket_recvfrom)(int fd, void *buf, int len, + uint32_t *src_ip, uint16_t *src_port); + int (*socket_sendto)(int fd, const void *buf, int len, + uint32_t dest_ip, uint16_t dest_port); + int (*socket_read)(int fd, void *buf, int len); + int (*socket_write)(int fd, const void *buf, int len); + void (*socket_close)(int fd); + void (*socket_set_recv_timeout)(int fd, int ms); + + // --- WiFi/MAC (for firewall + beacon + market) --- + bool (*get_sta_mac_ip_list)(void *list_out, int max, int *count_out); + bool (*set_vendor_ie)(bool enable, const void *ie_data, int ie_len); + int (*arp_get_mac)(uint32_t ip, uint8_t *mac_out); + void (*napt_enable)(uint32_t ip, bool enable); + + // --- Mining config --- + bool (*mining_enabled)(void); + const char* (*get_stratum_host)(void); + uint16_t (*get_stratum_port)(void); + const char* (*get_stratum_user)(void); + const char* (*get_stratum_pass)(void); + uint16_t (*get_mining_port)(void); + uint64_t (*get_hashprice_override)(void); + + // --- Random --- + void (*fill_random)(void *buf, int len); + +} tollgate_platform_t; +``` + +## Directory Structure + +``` +tollgate_core/ ← standalone C library (CMakeLists.txt, no ESP-IDF) + CMakeLists.txt + include/ + tollgate_core.h + tollgate_platform.h + src/ + tollgate_core.c + tollgate_cashu.c/h + tollgate_session.c/h + tollgate_dns.c/h + tollgate_firewall.c/h + tollgate_mining.c/h + tollgate_stratum_client.c/h + tollgate_stratum_proxy.c/h + tollgate_beacon.c/h + tollgate_market.c/h + +components/tollgate_esp/ ← ESP-IDF component wrapper + CMakeLists.txt + idf_component.yml + src/ + tollgate_esp_platform.c + tollgate_esp_http.c + tollgate_esp_sockets.c + tollgate_esp_wifi.c + tollgate_esp_wallet.c + tollgate_esp_tasks.c + +main/ ← esp32-tollgate specific (shrinks) + tollgate_main.c, tollgate_api.c, captive_portal.c + config.c, identity.c, nostr_event.c, wifistr.c + cvm_server.c, mcp_handler.c, local_relay.c + relay_selector.c, sync_manager.c + display.c, font.c + mint_health.c, tollgate_client.c +``` + +--- + +## Implementation Phases + +### Phase 0: Housekeeping + +- [x] Archive stale branches to `/home/c03rad0r/mining-work-backup/` as git bundles +- [x] Commit `PLAN_pytest_migration.md` +- [x] Fix `nucula_src` submodule drift +- [ ] Fix missing unit test build rules (`test_relay_selector.c`, `test_relay_validator.c`) +- [ ] Remove broken test binaries from TESTS list (`test_display`, `test_negentropy_adapter`) +- [ ] Run `make test-unit` — confirm green baseline +- [ ] Create branch `feature/tollgate-core-v2` from master + +### Phase 1: Create Skeleton + +- [ ] Create `tollgate_core/` directory with `CMakeLists.txt`, `include/`, `src/` +- [ ] Define `tollgate_platform.h` interface (all callbacks) +- [ ] Define `tollgate_core.h` public API +- [ ] Create empty `tollgate_core.c` with `tollgate_core_init()`, `tollgate_core_tick()` +- [ ] Create `components/tollgate_esp/` skeleton with empty `tollgate_esp_platform.c` +- [ ] Wire into `main/CMakeLists.txt` as dependency +- [ ] Verify: project builds, runs on hardware, no behavioral change + +### Phase 2: Extract Layer 0 — Pure Logic + +- [ ] `tollgate_cashu.c` — token decode, allotment math, checkstate (via platform HTTP) +- [ ] `tollgate_session.c` — lifecycle, expiry, extend, bytes/time support +- [ ] `tollgate_mining.c` — hashprice, nbits→difficulty, shares-to-allotment, client stats +- [ ] Port unit tests to test `tollgate_core/` directly (no ESP-IDF stubs) +- [ ] Verify: `make test-unit` passes with new tests + +### Phase 3: Extract Layer 1 — Protocol Logic + +- [ ] `tollgate_dns.c` — DNS protocol parser, hijack, forward, per-client auth +- [ ] `tollgate_firewall.c` — client allowlist, NAT filter, lwIP hook +- [ ] `tollgate_stratum_client.c` — SV1 pool client (subscribe, authorize, submit) +- [ ] `tollgate_stratum_proxy.c` — SV1 local proxy (TCP server, job broadcast) +- [ ] `tollgate_beacon.c` — Vendor IE builder/parser +- [ ] `tollgate_market.c` — price scanner, LRU entries, cheapest finder +- [ ] Wire `tollgate_core.c` orchestrator to all subsystems +- [ ] Verify: Build on hardware, run all integration tests + +### Phase 4: ESP-IDF Wrapper + +- [ ] `tollgate_esp_platform.c` — implement all `tollgate_platform_t` callbacks +- [ ] `components/tollgate_esp/CMakeLists.txt` — REQUIRES tollgate_core + ESP-IDF +- [ ] `components/tollgate_esp/idf_component.yml` — IDF Component Registry +- [ ] Verify: Full build + flash + all tests pass on Board A + +### Phase 5: Wire main/ to Use tollgate_core + +- [ ] Update `main/tollgate_main.c` — replace direct calls with tollgate_core API +- [ ] Update `main/tollgate_api.c` — payment → `tollgate_core_process_payment()` +- [ ] Update `main/captive_portal.c` — grant/reset → tollgate_core calls +- [ ] Remove old `main/session.c`, `main/firewall.c`, `main/dns_server.c`, `main/cashu.c`, etc. +- [ ] Verify: `make test-unit` passes, flash to board, run `make pytest-all-a` + +### Phase 6: NerdQAxePlus Integration + +- [ ] Update `main/tollgate_platform.cpp` to implement new `tollgate_platform_t` +- [ ] Wire `asic_result_task.cpp` → `tollgate_core_process_share()` +- [ ] Wire `main.cpp` → `tollgate_core_init()` + `tollgate_core_dns_start()` + `tollgate_core_tick()` +- [ ] Verify: `BOARD=NERDAXE TOLLGATE=1 idf.py build` passes + +### Phase 7: Publishing + CI + +- [ ] Publish `tollgate_esp` component to IDF Component Registry +- [ ] Add CI pipeline: build tollgate_core with host gcc + run pure-logic tests +- [ ] Add CI pipeline: build tollgate_esp for ESP32-S3 target +- [ ] Update documentation + +--- + +## Risks and Mitigations + +| Risk | Impact | Mitigation | +|------|--------|------------| +| RAM budget — tollgate_core statics consume more memory | Board crashes | Profile before/after with `heap_caps_get_free_size`. Keep static arrays same size. | +| Platform callback overhead on hot path (firewall) | Performance | Firewall filter already a function pointer. No extra overhead. | +| nucula_lib coupling — C++ but core is C | Build complexity | Wallet stays behind platform callback. Core never includes nucula headers. | +| Existing branches have useful work | Lost effort | Archived to `/home/c03rad0r/mining-work-backup/` as git bundles. | +| Test breakage during extraction | Regression | Run full test suite after each phase. Commit after each green phase. | + +## Estimated Time + +| Phase | Description | Time | +|-------|-------------|------| +| 0 | Housekeeping | 30 min | +| 1 | Skeleton | 2 hours | +| 2 | Layer 0: Pure logic | 4 hours | +| 3 | Layer 1: Protocol logic | 6 hours | +| 4 | ESP-IDF wrapper | 4 hours | +| 5 | Wire main/ | 6 hours | +| 6 | NerdQAxePlus integration | 4 hours | +| 7 | Publishing + CI | 2 hours | +| **Total** | | **~29 hours** | diff --git a/tests/unit/Makefile b/tests/unit/Makefile index b0b6922..cb06472 100644 --- a/tests/unit/Makefile +++ b/tests/unit/Makefile @@ -22,7 +22,7 @@ LDFLAGS := -lmbedcrypto -lcjson -lm SECP256K1_OBJ := secp256k1.o precomputed_ecmult.o precomputed_ecmult_gen.o -TESTS := test_geohash test_identity test_nostr_event test_cashu test_session test_tollgate_client test_lnurl_pay test_lightning_payout test_mcp_handler test_nip04 test_cvm_server test_display test_negentropy_adapter test_beacon_price test_market test_mint_health test_mining_payment test_stratum_proxy test_session_payment_method test_tollgate_client_mining test_firewall_sandbox +TESTS := test_geohash test_identity test_nostr_event test_cashu test_session test_tollgate_client test_lnurl_pay test_lightning_payout test_mcp_handler test_nip04 test_cvm_server test_beacon_price test_market test_mint_health test_mining_payment test_stratum_proxy test_session_payment_method test_tollgate_client_mining test_firewall_sandbox test_relay_selector test_relay_validator .PHONY: all test clean $(TESTS) @@ -105,5 +105,11 @@ test_tollgate_client_mining: test_tollgate_client_mining.c test_firewall_sandbox: test_firewall_sandbox.c $(REPO_ROOT)/main/firewall.c $(CC) $(CFLAGS) -include stubs/dns_server.h $< $(REPO_ROOT)/main/firewall.c -o $@ $(LDFLAGS) +test_relay_selector: test_relay_selector.c + $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) + +test_relay_validator: test_relay_validator.c $(REPO_ROOT)/main/nostr_event.c $(REPO_ROOT)/main/identity.c $(REPO_ROOT)/components/wisp_relay/relay_validator.c $(SECP256K1_OBJ) + $(CC) $(CFLAGS) -I $(SECP256K1_PRIV_INC) -I $(REPO_ROOT)/main -I $(REPO_ROOT)/components/wisp_relay $< $(REPO_ROOT)/main/nostr_event.c $(REPO_ROOT)/main/identity.c $(REPO_ROOT)/components/wisp_relay/relay_validator.c $(SECP256K1_OBJ) -o $@ $(LDFLAGS) + clean: rm -f $(TESTS) $(SECP256K1_OBJ) diff --git a/tests/unit/stubs/freertos/FreeRTOS.h b/tests/unit/stubs/freertos/FreeRTOS.h index 543d4e4..fc38846 100644 --- a/tests/unit/stubs/freertos/FreeRTOS.h +++ b/tests/unit/stubs/freertos/FreeRTOS.h @@ -11,6 +11,7 @@ static inline uint32_t xTaskGetTickCount(void) { return 0; } static inline void vTaskDelay(uint32_t ticks) { (void)ticks; } #define pdMS_TO_TICKS(ms) ((ms) / 10) #define portTICK_PERIOD_MS 10 +#define configTICK_RATE_HZ 100 #define portMAX_DELAY 0xFFFFFFFF #define pdTRUE 1 #define pdFALSE 0 diff --git a/tests/unit/test_beacon_price b/tests/unit/test_beacon_price deleted file mode 100755 index a9f6357..0000000 Binary files a/tests/unit/test_beacon_price and /dev/null differ diff --git a/tests/unit/test_display b/tests/unit/test_display deleted file mode 100755 index 9b8364e..0000000 Binary files a/tests/unit/test_display and /dev/null differ diff --git a/tests/unit/test_firewall_sandbox b/tests/unit/test_firewall_sandbox deleted file mode 100755 index 3e2895b..0000000 Binary files a/tests/unit/test_firewall_sandbox and /dev/null differ diff --git a/tests/unit/test_market b/tests/unit/test_market deleted file mode 100755 index 8efac8e..0000000 Binary files a/tests/unit/test_market and /dev/null differ diff --git a/tests/unit/test_mining_payment b/tests/unit/test_mining_payment deleted file mode 100755 index d38bf9d..0000000 Binary files a/tests/unit/test_mining_payment and /dev/null differ diff --git a/tests/unit/test_negentropy_adapter b/tests/unit/test_negentropy_adapter deleted file mode 100755 index 64b6053..0000000 Binary files a/tests/unit/test_negentropy_adapter and /dev/null differ diff --git a/tests/unit/test_session_payment_method b/tests/unit/test_session_payment_method deleted file mode 100755 index 950a72f..0000000 Binary files a/tests/unit/test_session_payment_method and /dev/null differ diff --git a/tests/unit/test_stratum_proxy b/tests/unit/test_stratum_proxy deleted file mode 100755 index 963df67..0000000 Binary files a/tests/unit/test_stratum_proxy and /dev/null differ diff --git a/tests/unit/test_tollgate_client_mining b/tests/unit/test_tollgate_client_mining deleted file mode 100755 index d331bd1..0000000 Binary files a/tests/unit/test_tollgate_client_mining and /dev/null differ -- cgit v1.2.3