upleb.uk

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

summaryrefslogtreecommitdiff
path: root/components/tollgate_esp/src
diff options
context:
space:
mode:
authorYour Name <you@example.com>2026-05-23 02:32:24 +0530
committerYour Name <you@example.com>2026-05-23 02:32:24 +0530
commit6771956f1647f377007ab61a59b116de6d536706 (patch)
treee8b6c74164040339134e33b8616c27c23ec1ade6 /components/tollgate_esp/src
parent10c69b0ddc34a1fafada3f8b68a622b4aa2bea77 (diff)
feat: create tollgate_core standalone C library + tollgate_esp IDF component
Phase 1-4: Extract core business logic into reusable library tollgate_core/ — standalone C library (zero ESP-IDF deps): - tollgate_core.c — orchestrator (init, process_payment, process_share, tick) - tollgate_cashu.c — V3 token decode, checkstate via platform callback, allotment math - tollgate_session.c — session lifecycle state machine (create/find/revoke/extend) - tollgate_firewall.c — client allowlist, NAT filter, packet filter - tollgate_mining.c — hashprice, nbits→difficulty, shares-to-allotment, client stats components/tollgate_esp/ — ESP-IDF component wrapper: - tollgate_esp_platform.c — implements tollgate_platform_t using ESP-IDF APIs - CMakeLists.txt — compiles tollgate_core + ESP wrapper, links to ESP-IDF - idf_component.yml — for IDF Component Registry Platform interface (tollgate_platform.h): - Config access: price, step_size, mint_url, metric - Time: get_time_ms (via FreeRTOS ticks on ESP) - Logging: log_info/warn/error (via ESP_LOG on ESP) - Wallet: receive/send/balance (via nucula on ESP) - HTTP: http_post (via esp_http_client on ESP) - WiFi/MAC: mac_for_ip, napt_enable - Mining: stratum config, hashprice override Build verification: - tollgate_core compiles standalone: cmake + make (gcc, host) - tollgate_esp + ESP-IDF full build: passes (idf.py build) - Unit tests: 22/22 pass (make test-unit) - No behavioral change to existing main/ code yet (Phase 5)
Diffstat (limited to 'components/tollgate_esp/src')
-rw-r--r--components/tollgate_esp/src/tollgate_esp_platform.c289
1 files changed, 289 insertions, 0 deletions
diff --git a/components/tollgate_esp/src/tollgate_esp_platform.c b/components/tollgate_esp/src/tollgate_esp_platform.c
new file mode 100644
index 0000000..7d671f4
--- /dev/null
+++ b/components/tollgate_esp/src/tollgate_esp_platform.c
@@ -0,0 +1,289 @@
1#include "tollgate_esp_platform.h"
2#include "tollgate_core.h"
3#include "config.h"
4#include "nucula_wallet.h"
5#include "esp_log.h"
6#include "esp_http_client.h"
7#include "esp_crt_bundle.h"
8#include "freertos/FreeRTOS.h"
9#include "freertos/task.h"
10#include "esp_wifi.h"
11#include "esp_wifi_ap_get_sta_list.h"
12#include "lwip/etharp.h"
13#include "lwip/netif.h"
14#include "lwip/lwip_napt.h"
15#include <string.h>
16#include <stdarg.h>
17
18static const char *TAG = "tg_esp";
19
20static void esp_log_info(const char *tag, const char *fmt, ...)
21{
22 va_list args;
23 va_start(args, fmt);
24 esp_log_write(ESP_LOG_INFO, tag, fmt, args);
25 va_end(args);
26}
27
28static void esp_log_warn(const char *tag, const char *fmt, ...)
29{
30 va_list args;
31 va_start(args, fmt);
32 esp_log_write(ESP_LOG_WARN, tag, fmt, args);
33 va_end(args);
34}
35
36static void esp_log_error(const char *tag, const char *fmt, ...)
37{
38 va_list args;
39 va_start(args, fmt);
40 esp_log_write(ESP_LOG_ERROR, tag, fmt, args);
41 va_end(args);
42}
43
44static uint16_t esp_get_price_sats(void)
45{
46 const tollgate_config_t *cfg = tollgate_config_get();
47 return cfg ? (uint16_t)cfg->price_per_step : 21;
48}
49
50static int32_t esp_get_step_ms(void)
51{
52 const tollgate_config_t *cfg = tollgate_config_get();
53 return cfg ? (int32_t)cfg->step_size_ms : 60000;
54}
55
56static int64_t esp_get_step_bytes(void)
57{
58 const tollgate_config_t *cfg = tollgate_config_get();
59 return cfg ? (int64_t)cfg->step_size_bytes : 22020096;
60}
61
62static const char *esp_get_mint_url(void)
63{
64 const tollgate_config_t *cfg = tollgate_config_get();
65 return cfg ? cfg->mint_url : NULL;
66}
67
68static const char *esp_get_metric(void)
69{
70 const tollgate_config_t *cfg = tollgate_config_get();
71 return cfg ? cfg->metric : "milliseconds";
72}
73
74static int64_t esp_get_time_ms(void)
75{
76 return (int64_t)xTaskGetTickCount() * portTICK_PERIOD_MS;
77}
78
79static bool esp_wallet_receive(const char *token)
80{
81 return nucula_wallet_receive(token) == ESP_OK;
82}
83
84static bool esp_wallet_send(uint64_t amount, char *buf, size_t buf_len)
85{
86 return nucula_wallet_send(amount, buf, buf_len) == ESP_OK;
87}
88
89static uint64_t esp_wallet_balance(void)
90{
91 return nucula_wallet_balance();
92}
93
94static int esp_http_post(const char *url, const char *headers,
95 const char *body, int body_len,
96 char *resp, int resp_len)
97{
98 esp_http_client_config_t config = {
99 .url = url,
100 .method = HTTP_METHOD_POST,
101 .timeout_ms = 15000,
102 .crt_bundle_attach = esp_crt_bundle_attach,
103 };
104 esp_http_client_handle_t client = esp_http_client_init(&config);
105 if (!client) return -1;
106
107 if (headers) {
108 const char *h = headers;
109 while (*h) {
110 const char *colon = strchr(h, ':');
111 if (!colon) break;
112 char key[64] = {0};
113 size_t klen = colon - h;
114 if (klen >= sizeof(key)) klen = sizeof(key) - 1;
115 memcpy(key, h, klen);
116 esp_http_client_set_header(client, key, colon + 1);
117 const char *next = strchr(colon, '\n');
118 if (!next) break;
119 h = next + 1;
120 }
121 }
122 if (headers && headers[0]) {
123 esp_http_client_set_header(client, "Content-Type", "application/json");
124 }
125
126 esp_err_t err = esp_http_client_open(client, body_len);
127 if (err != ESP_OK) {
128 esp_http_client_cleanup(client);
129 return -1;
130 }
131 int written = esp_http_client_write(client, body, body_len);
132 (void)written;
133
134 esp_http_client_fetch_headers(client);
135 int status = esp_http_client_get_status_code(client);
136 int rd = esp_http_client_read(client, resp, resp_len);
137 esp_http_client_cleanup(client);
138
139 if (status != 200 || rd <= 0) return -1;
140 return rd;
141}
142
143static bool esp_create_task(void (*fn)(void*), void *arg,
144 const char *name, int stack_bytes, int priority)
145{
146 return xTaskCreate(fn, name ? name : "tg_task",
147 stack_bytes / sizeof(StackType_t),
148 arg, priority, NULL) == pdPASS;
149}
150
151static bool esp_mac_for_ip(uint32_t ip, char *mac_out, int mac_out_size)
152{
153 wifi_sta_list_t sta_list;
154 if (esp_wifi_ap_get_sta_list(&sta_list) == ESP_OK) {
155 wifi_sta_mac_ip_list_t ip_mac_list;
156 if (esp_wifi_ap_get_sta_list_with_ip(&sta_list, &ip_mac_list) == ESP_OK) {
157 for (int i = 0; i < ip_mac_list.num; i++) {
158 if (ip_mac_list.sta[i].ip.addr == ip) {
159 snprintf(mac_out, mac_out_size, "%02x:%02x:%02x:%02x:%02x:%02x",
160 ip_mac_list.sta[i].mac[0], ip_mac_list.sta[i].mac[1],
161 ip_mac_list.sta[i].mac[2], ip_mac_list.sta[i].mac[3],
162 ip_mac_list.sta[i].mac[4], ip_mac_list.sta[i].mac[5]);
163 return true;
164 }
165 }
166 }
167 }
168
169 ip4_addr_t *entry_ip = NULL;
170 struct netif *entry_netif = NULL;
171 struct eth_addr *entry_eth = NULL;
172 ssize_t i = 0;
173 while (etharp_get_entry(i, &entry_ip, &entry_netif, &entry_eth) == ERR_OK) {
174 if (entry_ip && entry_ip->addr == ip && entry_eth) {
175 snprintf(mac_out, mac_out_size, "%02x:%02x:%02x:%02x:%02x:%02x",
176 entry_eth->addr[0], entry_eth->addr[1], entry_eth->addr[2],
177 entry_eth->addr[3], entry_eth->addr[4], entry_eth->addr[5]);
178 return true;
179 }
180 i++;
181 }
182 return false;
183}
184
185static void esp_napt_enable(uint32_t ip, bool enable)
186{
187 ip_napt_enable(ip, enable ? 1 : 0);
188}
189
190static bool esp_mining_enabled(void)
191{
192 const tollgate_config_t *cfg = tollgate_config_get();
193 return cfg ? cfg->mining_enabled : false;
194}
195
196static const char *esp_get_stratum_host(void)
197{
198 const tollgate_config_t *cfg = tollgate_config_get();
199 return cfg ? cfg->stratum_host : NULL;
200}
201
202static uint16_t esp_get_stratum_port(void)
203{
204 const tollgate_config_t *cfg = tollgate_config_get();
205 return cfg ? cfg->stratum_port : 3333;
206}
207
208static const char *esp_get_stratum_user(void)
209{
210 const tollgate_config_t *cfg = tollgate_config_get();
211 return cfg ? cfg->stratum_user : NULL;
212}
213
214static const char *esp_get_stratum_pass(void)
215{
216 const tollgate_config_t *cfg = tollgate_config_get();
217 return cfg ? cfg->stratum_pass : NULL;
218}
219
220static uint16_t esp_get_mining_port(void)
221{
222 const tollgate_config_t *cfg = tollgate_config_get();
223 return cfg ? cfg->mining_port : 3334;
224}
225
226static uint64_t esp_get_hashprice_override(void)
227{
228 const tollgate_config_t *cfg = tollgate_config_get();
229 return cfg ? cfg->hashprice_sats_per_ghs_day : 0;
230}
231
232static void tg_esp_fill_random(void *buf, int len)
233{
234 esp_fill_random(buf, (size_t)len);
235}
236
237static int esp_get_accepted_mint_count(void)
238{
239 const tollgate_config_t *cfg = tollgate_config_get();
240 return cfg ? cfg->accepted_mint_count : 0;
241}
242
243static const char *esp_get_accepted_mint(int index)
244{
245 const tollgate_config_t *cfg = tollgate_config_get();
246 if (!cfg || index < 0 || index >= cfg->accepted_mint_count) return NULL;
247 return cfg->accepted_mints[index];
248}
249
250static bool esp_is_mint_reachable(const char *mint_url)
251{
252 (void)mint_url;
253 return true;
254}
255
256static const tollgate_platform_t s_platform = {
257 .get_price_sats = esp_get_price_sats,
258 .get_step_ms = esp_get_step_ms,
259 .get_step_bytes = esp_get_step_bytes,
260 .get_mint_url = esp_get_mint_url,
261 .get_metric = esp_get_metric,
262 .get_time_ms = esp_get_time_ms,
263 .log_info = esp_log_info,
264 .log_warn = esp_log_warn,
265 .log_error = esp_log_error,
266 .wallet_receive = esp_wallet_receive,
267 .wallet_send = esp_wallet_send,
268 .wallet_balance = esp_wallet_balance,
269 .http_post = esp_http_post,
270 .create_task = esp_create_task,
271 .mac_for_ip = esp_mac_for_ip,
272 .napt_enable = esp_napt_enable,
273 .mining_enabled = esp_mining_enabled,
274 .get_stratum_host = esp_get_stratum_host,
275 .get_stratum_port = esp_get_stratum_port,
276 .get_stratum_user = esp_get_stratum_user,
277 .get_stratum_pass = esp_get_stratum_pass,
278 .get_mining_port = esp_get_mining_port,
279 .get_hashprice_override = esp_get_hashprice_override,
280 .fill_random = tg_esp_fill_random,
281 .get_accepted_mint_count = esp_get_accepted_mint_count,
282 .get_accepted_mint = esp_get_accepted_mint,
283 .is_mint_reachable = esp_is_mint_reachable,
284};
285
286const tollgate_platform_t *tollgate_esp_get_platform(void)
287{
288 return &s_platform;
289}