upleb.uk

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

summaryrefslogtreecommitdiff
path: root/components/tollgate_core/src
diff options
context:
space:
mode:
authorYour Name <you@example.com>2026-05-20 02:20:15 +0530
committerYour Name <you@example.com>2026-05-20 02:20:15 +0530
commitf922e8a676431f33d6133fc021d384bbdfd76f17 (patch)
tree84d210d66d0969905496f23dfdd23f2429a11142 /components/tollgate_core/src
parentf4f85f938405867be89cfee029d5117cb1b4ac69 (diff)
feat: upgrade tollgate_core to full version with mining + stratum
Replace skeleton tollgate_core (9 files, 7 callbacks) with full version from feature/miner-integration (13 files, 22 callbacks): New modules: - tollgate_core_mining.c/h — mining payment session management - tollgate_core_stratum_proxy.c/h — SV1 stratum proxy Updated: - tollgate_core.h — extern C guards, 5 new mining API functions - tollgate_platform.h — extern C guards, 22 platform callbacks (was 7) - tollgate_core_firewall.c — conditional CONFIG_LWIP_IPV4_NAPT - CMakeLists.txt — mining + stratum source files Also adds MINER_INTEGRATION_PLAN.md from the feature branch.
Diffstat (limited to 'components/tollgate_core/src')
-rw-r--r--components/tollgate_core/src/tollgate_core_firewall.c4
-rw-r--r--components/tollgate_core/src/tollgate_core_mining.c168
-rw-r--r--components/tollgate_core/src/tollgate_core_mining.h35
-rw-r--r--components/tollgate_core/src/tollgate_core_stratum_proxy.c160
-rw-r--r--components/tollgate_core/src/tollgate_core_stratum_proxy.h39
5 files changed, 406 insertions, 0 deletions
diff --git a/components/tollgate_core/src/tollgate_core_firewall.c b/components/tollgate_core/src/tollgate_core_firewall.c
index e5d61d8..ad0697e 100644
--- a/components/tollgate_core/src/tollgate_core_firewall.c
+++ b/components/tollgate_core/src/tollgate_core_firewall.c
@@ -3,7 +3,9 @@
3#include "esp_log.h" 3#include "esp_log.h"
4#include "esp_wifi.h" 4#include "esp_wifi.h"
5#include "esp_wifi_ap_get_sta_list.h" 5#include "esp_wifi_ap_get_sta_list.h"
6#ifdef CONFIG_LWIP_IPV4_NAPT
6#include "lwip/lwip_napt.h" 7#include "lwip/lwip_napt.h"
8#endif
7#include "lwip/etharp.h" 9#include "lwip/etharp.h"
8#include "lwip/netif.h" 10#include "lwip/netif.h"
9#include "lwip/prot/ip4.h" 11#include "lwip/prot/ip4.h"
@@ -61,7 +63,9 @@ esp_err_t tollgate_core_fw_init(esp_ip4_addr_t ap_ip)
61 s_ap_ip = ap_ip; 63 s_ap_ip = ap_ip;
62 memset(s_clients, 0, sizeof(s_clients)); 64 memset(s_clients, 0, sizeof(s_clients));
63 s_client_count = 0; 65 s_client_count = 0;
66#ifdef CONFIG_LWIP_IPV4_NAPT
64 ip_napt_enable(s_ap_ip.addr, 1); 67 ip_napt_enable(s_ap_ip.addr, 1);
68#endif
65 ESP_LOGI(TAG, "Firewall initialized with AP IP=" IPSTR " (NAT always on, per-client filter)", IP2STR(&s_ap_ip)); 69 ESP_LOGI(TAG, "Firewall initialized with AP IP=" IPSTR " (NAT always on, per-client filter)", IP2STR(&s_ap_ip));
66 return ESP_OK; 70 return ESP_OK;
67} 71}
diff --git a/components/tollgate_core/src/tollgate_core_mining.c b/components/tollgate_core/src/tollgate_core_mining.c
new file mode 100644
index 0000000..e656f33
--- /dev/null
+++ b/components/tollgate_core/src/tollgate_core_mining.c
@@ -0,0 +1,168 @@
1#include "tollgate_core_mining.h"
2#include "esp_log.h"
3#include "freertos/FreeRTOS.h"
4#include "freertos/task.h"
5#include <string.h>
6#include <math.h>
7
8static const char *TAG = "tollgate_core_mining";
9
10static tollgate_mining_client_stats_t s_clients[MINING_MAX_CLIENTS];
11static int s_client_count = 0;
12static double s_current_hashprice = 0.0;
13static uint32_t s_current_nbits = 0;
14static uint64_t s_current_difficulty = 1;
15
16static int64_t get_time_ms(void)
17{
18 return (int64_t)xTaskGetTickCount() * portTICK_PERIOD_MS;
19}
20
21uint64_t tollgate_core_mining_nbits_to_difficulty(uint32_t nbits)
22{
23 if (nbits == 0) return UINT64_MAX;
24
25 uint32_t exponent = (nbits >> 24) & 0xFF;
26 uint32_t mantissa = nbits & 0x007FFFFF;
27
28 if (exponent <= 3) {
29 mantissa >>= (8 * (3 - exponent));
30 if (mantissa == 0) return UINT64_MAX;
31 return 0x00000000FFFF0000ULL / mantissa;
32 }
33
34 uint64_t target = (uint64_t)mantissa << (8 * (exponent - 3));
35 if (target == 0) return UINT64_MAX;
36
37 uint64_t pdiff = 0x00000000FFFF0000ULL;
38 uint64_t diff = pdiff / (target >> (exponent > 7 ? 0 : 0));
39 if (diff == 0) diff = 1;
40 return diff;
41}
42
43double tollgate_core_mining_calc_hashprice(uint32_t nbits)
44{
45 uint64_t diff = tollgate_core_mining_nbits_to_difficulty(nbits);
46 if (diff == 0 || diff == UINT64_MAX) return 0.0;
47
48 double network_hashrate_th = (double)diff * 4294967296.0 / 1e12;
49 double daily_sats = (double)MINING_BLOCK_SUBSIDY_SATS * (double)MINING_BLOCKS_PER_DAY;
50 double sats_per_th_day = daily_sats / network_hashrate_th;
51 return sats_per_th_day / 1000.0;
52}
53
54double tollgate_core_mining_calc_hashprice_override(uint64_t sats_per_ghs_day)
55{
56 return (double)sats_per_ghs_day;
57}
58
59esp_err_t tollgate_core_mining_validate_share(const uint8_t *header80, uint32_t nonce, const uint8_t *target, int target_len)
60{
61 (void)header80;
62 (void)nonce;
63 (void)target;
64 (void)target_len;
65 return ESP_OK;
66}
67
68uint64_t tollgate_core_mining_shares_to_allotment_ms(double hashrate_ghs, double hashprice_sats_per_ghs_s,
69 int price_per_step, int step_size_ms)
70{
71 if (hashrate_ghs <= 0.0 || hashprice_sats_per_ghs_s <= 0.0 || price_per_step <= 0) return 0;
72
73 double sats_per_ms = hashrate_ghs * hashprice_sats_per_ghs_s / 86400000.0;
74 double steps_earned = sats_per_ms * (double)step_size_ms / (double)price_per_step;
75 uint64_t allotment = (uint64_t)(steps_earned * (double)step_size_ms);
76 return allotment > 0 ? allotment : 1;
77}
78
79uint64_t tollgate_core_mining_shares_to_allotment_bytes(double hashrate_ghs, double hashprice_sats_per_ghs_s,
80 int price_per_step, int step_size_bytes)
81{
82 if (hashrate_ghs <= 0.0 || hashprice_sats_per_ghs_s <= 0.0 || price_per_step <= 0) return 0;
83
84 double sats_per_ms = hashrate_ghs * hashprice_sats_per_ghs_s / 86400000.0;
85 double steps_earned = sats_per_ms * 1000.0 / (double)price_per_step;
86 uint64_t allotment = (uint64_t)(steps_earned * (double)step_size_bytes);
87 return allotment > 0 ? allotment : 1;
88}
89
90tollgate_mining_client_stats_t *tollgate_core_mining_get_or_create_client(uint32_t client_ip)
91{
92 for (int i = 0; i < s_client_count; i++) {
93 if (s_clients[i].ip == client_ip) return &s_clients[i];
94 }
95
96 if (s_client_count >= MINING_MAX_CLIENTS) {
97 for (int i = 0; i < MINING_MAX_CLIENTS; i++) {
98 int64_t age = get_time_ms() - s_clients[i].last_share_time_ms;
99 if (age > MINING_SHARE_WINDOW_S * 2000) {
100 memset(&s_clients[i], 0, sizeof(tollgate_mining_client_stats_t));
101 s_clients[i].ip = client_ip;
102 s_clients[i].first_share_time_ms = get_time_ms();
103 return &s_clients[i];
104 }
105 }
106 return NULL;
107 }
108
109 tollgate_mining_client_stats_t *c = &s_clients[s_client_count];
110 memset(c, 0, sizeof(tollgate_mining_client_stats_t));
111 c->ip = client_ip;
112 c->first_share_time_ms = get_time_ms();
113 s_client_count++;
114 return c;
115}
116
117void tollgate_core_mining_update_hashrate(uint32_t client_ip, bool accepted)
118{
119 tollgate_mining_client_stats_t *stats = tollgate_core_mining_get_or_create_client(client_ip);
120 if (!stats) return;
121
122 if (accepted) {
123 stats->shares_accepted++;
124 } else {
125 stats->shares_rejected++;
126 }
127 stats->last_share_time_ms = get_time_ms();
128
129 int64_t window_ms = stats->last_share_time_ms - stats->first_share_time_ms;
130 if (window_ms < 1000) window_ms = 1000;
131
132 double window_s = (double)window_ms / 1000.0;
133 double shares_per_s = (double)stats->shares_accepted / window_s;
134 double diff = (s_current_difficulty > 0) ? (double)s_current_difficulty : 1.0;
135 stats->hashrate_ghs = shares_per_s * diff * 4294967296.0 / 1e9;
136}
137
138const tollgate_mining_client_stats_t *tollgate_core_mining_get_client_stats(uint32_t client_ip)
139{
140 for (int i = 0; i < s_client_count; i++) {
141 if (s_clients[i].ip == client_ip) return &s_clients[i];
142 }
143 return NULL;
144}
145
146double tollgate_core_mining_get_current_hashprice(void)
147{
148 return s_current_hashprice;
149}
150
151void tollgate_core_mining_set_current_nbits(uint32_t nbits)
152{
153 s_current_nbits = nbits;
154 s_current_difficulty = tollgate_core_mining_nbits_to_difficulty(nbits);
155 s_current_hashprice = tollgate_core_mining_calc_hashprice(nbits);
156 ESP_LOGI(TAG, "nbits updated: 0x%08lx, diff=%llu, hashprice=%.6f sat/GH/s/day",
157 (unsigned long)nbits, (unsigned long long)s_current_difficulty, s_current_hashprice);
158}
159
160void tollgate_core_mining_init(void)
161{
162 memset(s_clients, 0, sizeof(s_clients));
163 s_client_count = 0;
164 s_current_hashprice = 0.0;
165 s_current_nbits = 0;
166 s_current_difficulty = 1;
167 ESP_LOGI(TAG, "Mining payment module initialized");
168}
diff --git a/components/tollgate_core/src/tollgate_core_mining.h b/components/tollgate_core/src/tollgate_core_mining.h
new file mode 100644
index 0000000..442e33a
--- /dev/null
+++ b/components/tollgate_core/src/tollgate_core_mining.h
@@ -0,0 +1,35 @@
1#ifndef TOLLGATE_CORE_MINING_H
2#define TOLLGATE_CORE_MINING_H
3
4#include "esp_err.h"
5#include <stdint.h>
6#include <stdbool.h>
7
8#define MINING_SHARE_WINDOW_S 30
9#define MINING_BLOCK_SUBSIDY_SATS 312500000ULL
10#define MINING_BLOCKS_PER_DAY 144ULL
11#define MINING_MAX_CLIENTS 10
12
13typedef struct {
14 uint32_t ip;
15 uint64_t shares_accepted;
16 uint64_t shares_rejected;
17 int64_t first_share_time_ms;
18 int64_t last_share_time_ms;
19 double hashrate_ghs;
20} tollgate_mining_client_stats_t;
21
22uint64_t tollgate_core_mining_nbits_to_difficulty(uint32_t nbits);
23double tollgate_core_mining_calc_hashprice(uint32_t nbits);
24double tollgate_core_mining_calc_hashprice_override(uint64_t sats_per_ghs_day);
25esp_err_t tollgate_core_mining_validate_share(const uint8_t *header80, uint32_t nonce, const uint8_t *target, int target_len);
26uint64_t tollgate_core_mining_shares_to_allotment_ms(double hashrate_ghs, double hashprice, int price, int step_ms);
27uint64_t tollgate_core_mining_shares_to_allotment_bytes(double hashrate_ghs, double hashprice, int price, int step_bytes);
28tollgate_mining_client_stats_t *tollgate_core_mining_get_or_create_client(uint32_t client_ip);
29void tollgate_core_mining_update_hashrate(uint32_t client_ip, bool accepted);
30const tollgate_mining_client_stats_t *tollgate_core_mining_get_client_stats(uint32_t client_ip);
31double tollgate_core_mining_get_current_hashprice(void);
32void tollgate_core_mining_set_current_nbits(uint32_t nbits);
33void tollgate_core_mining_init(void);
34
35#endif
diff --git a/components/tollgate_core/src/tollgate_core_stratum_proxy.c b/components/tollgate_core/src/tollgate_core_stratum_proxy.c
new file mode 100644
index 0000000..105df14
--- /dev/null
+++ b/components/tollgate_core/src/tollgate_core_stratum_proxy.c
@@ -0,0 +1,160 @@
1#include "tollgate_core_stratum_proxy.h"
2#include "tollgate_core_mining.h"
3#include "esp_log.h"
4#include "lwip/sockets.h"
5#include "freertos/FreeRTOS.h"
6#include "freertos/task.h"
7#include <string.h>
8
9static const char *TAG = "tollgate_core_stratum";
10static uint16_t s_port = 3333;
11static bool s_running = false;
12static TaskHandle_t s_task_handle = NULL;
13static int s_server_fd = -1;
14
15static tollgate_stratum_job_t s_current_job = {0};
16static tollgate_stratum_proxy_stats_t s_stats = {0};
17
18static void proxy_client_handler(void *arg)
19{
20 int client_fd = (int)(intptr_t)arg;
21 struct sockaddr_in client_addr;
22 socklen_t addr_len = sizeof(client_addr);
23 getpeername(client_fd, (struct sockaddr *)&client_addr, &addr_len);
24 uint32_t client_ip = client_addr.sin_addr.s_addr;
25
26 ESP_LOGI(TAG, "Miner connected from 0x%08lx", (unsigned long)client_ip);
27
28 if (s_current_job.valid) {
29 char job_json[512];
30 snprintf(job_json, sizeof(job_json),
31 "{\"id\":1,\"method\":\"mining.notify\",\"params\":[\"%lu\",\"%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx\",\"\",\"\",\"\",\"%08lx\",\"%08lx\",\"%08lx\",true]}\n",
32 (unsigned long)s_current_job.job_id,
33 (unsigned long)0, (unsigned long)0, (unsigned long)0, (unsigned long)0,
34 (unsigned long)0, (unsigned long)0, (unsigned long)0, (unsigned long)0,
35 (unsigned long)s_current_job.nbits, (unsigned long)s_current_job.ntime,
36 (unsigned long)s_current_job.version);
37 send(client_fd, job_json, strlen(job_json), 0);
38 }
39
40 char buf[1024];
41 while (s_running) {
42 int len = recv(client_fd, buf, sizeof(buf) - 1, 0);
43 if (len <= 0) break;
44 buf[len] = '\0';
45
46 ESP_LOGI(TAG, "Received from miner: %s", buf);
47 s_stats.total_shares++;
48 s_stats.total_accepted++;
49 }
50
51 ESP_LOGI(TAG, "Miner disconnected from 0x%08lx", (unsigned long)client_ip);
52 close(client_fd);
53 vTaskDelete(NULL);
54}
55
56static void proxy_server_task(void *arg)
57{
58 struct sockaddr_in server_addr;
59 memset(&server_addr, 0, sizeof(server_addr));
60 server_addr.sin_family = AF_INET;
61 server_addr.sin_addr.s_addr = INADDR_ANY;
62 server_addr.sin_port = htons(s_port);
63
64 s_server_fd = socket(AF_INET, SOCK_STREAM, 0);
65 if (s_server_fd < 0) {
66 ESP_LOGE(TAG, "Failed to create socket");
67 vTaskDelete(NULL);
68 return;
69 }
70
71 int opt = 1;
72 setsockopt(s_server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
73
74 if (bind(s_server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0) {
75 ESP_LOGE(TAG, "Failed to bind to port %u", (unsigned)s_port);
76 close(s_server_fd);
77 s_server_fd = -1;
78 vTaskDelete(NULL);
79 return;
80 }
81
82 if (listen(s_server_fd, 5) != 0) {
83 ESP_LOGE(TAG, "Failed to listen");
84 close(s_server_fd);
85 s_server_fd = -1;
86 vTaskDelete(NULL);
87 return;
88 }
89
90 ESP_LOGI(TAG, "Stratum proxy listening on port %u", (unsigned)s_port);
91
92 while (s_running) {
93 struct sockaddr_in client_addr;
94 socklen_t client_len = sizeof(client_addr);
95 int client_fd = accept(s_server_fd, (struct sockaddr *)&client_addr, &client_len);
96 if (client_fd < 0) continue;
97
98 s_stats.active_miners++;
99 char task_name[20];
100 snprintf(task_name, sizeof(task_name), "miner_%d", client_fd);
101 xTaskCreate(proxy_client_handler, task_name, 4096, (void *)(intptr_t)client_fd, 3, NULL);
102 }
103
104 close(s_server_fd);
105 s_server_fd = -1;
106 vTaskDelete(NULL);
107}
108
109esp_err_t tollgate_core_stratum_proxy_init(uint16_t port)
110{
111 s_port = port;
112 memset(&s_current_job, 0, sizeof(s_current_job));
113 memset(&s_stats, 0, sizeof(s_stats));
114 s_running = true;
115
116 BaseType_t ret = xTaskCreate(proxy_server_task, "stratum_proxy", 4096, NULL, 4, &s_task_handle);
117 if (ret != pdPASS) {
118 ESP_LOGE(TAG, "Failed to create proxy task");
119 s_running = false;
120 return ESP_FAIL;
121 }
122
123 ESP_LOGI(TAG, "Stratum proxy initialized on port %u", (unsigned)port);
124 return ESP_OK;
125}
126
127void tollgate_core_stratum_proxy_set_job(const tollgate_stratum_job_t *job)
128{
129 if (job) {
130 memcpy(&s_current_job, job, sizeof(tollgate_stratum_job_t));
131 s_stats.nbits = job->nbits;
132 s_stats.current_hashprice = tollgate_core_mining_get_current_hashprice();
133 }
134}
135
136const tollgate_stratum_job_t *tollgate_core_stratum_proxy_get_current_job(void)
137{
138 return &s_current_job;
139}
140
141void tollgate_core_stratum_proxy_get_stats(tollgate_stratum_proxy_stats_t *stats)
142{
143 if (stats) {
144 *stats = s_stats;
145 stats->current_hashprice = tollgate_core_mining_get_current_hashprice();
146 }
147}
148
149void tollgate_core_stratum_proxy_stop(void)
150{
151 s_running = false;
152 if (s_server_fd >= 0) {
153 close(s_server_fd);
154 s_server_fd = -1;
155 }
156 if (s_task_handle) {
157 vTaskDelay(pdMS_TO_TICKS(500));
158 s_task_handle = NULL;
159 }
160}
diff --git a/components/tollgate_core/src/tollgate_core_stratum_proxy.h b/components/tollgate_core/src/tollgate_core_stratum_proxy.h
new file mode 100644
index 0000000..42f2fb1
--- /dev/null
+++ b/components/tollgate_core/src/tollgate_core_stratum_proxy.h
@@ -0,0 +1,39 @@
1#ifndef TOLLGATE_CORE_STRATUM_PROXY_H
2#define TOLLGATE_CORE_STRATUM_PROXY_H
3
4#include "esp_err.h"
5#include <stdint.h>
6#include <stdbool.h>
7
8#define TOLLGATE_STRATUM_MAX_JOB_ID_LEN 32
9#define TOLLGATE_STRATUM_MAX_JOBS 4
10
11typedef struct {
12 uint32_t job_id;
13 uint8_t prevhash[32];
14 uint8_t merkle_root[32];
15 uint32_t ntime;
16 uint32_t nbits;
17 uint32_t version;
18 uint8_t target[32];
19 int target_len;
20 bool valid;
21} tollgate_stratum_job_t;
22
23typedef struct {
24 double hashrate_ghs;
25 uint32_t nbits;
26 uint64_t total_shares;
27 uint64_t total_accepted;
28 uint64_t total_rejected;
29 double current_hashprice;
30 int active_miners;
31} tollgate_stratum_proxy_stats_t;
32
33esp_err_t tollgate_core_stratum_proxy_init(uint16_t port);
34void tollgate_core_stratum_proxy_set_job(const tollgate_stratum_job_t *job);
35const tollgate_stratum_job_t *tollgate_core_stratum_proxy_get_current_job(void);
36void tollgate_core_stratum_proxy_get_stats(tollgate_stratum_proxy_stats_t *stats);
37void tollgate_core_stratum_proxy_stop(void);
38
39#endif