From be4d490e96de3d20cc6c9921f09534cde0ca0765 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 23 May 2026 15:26:52 +0530 Subject: Phase 8c-8f: Extract portal, stratum_client, mint_health, client into tollgate_core New component modules: - tollgate_core_portal.c/h: template rendering, usage calc, captive URI detection - tollgate_core_stratum_client.c/h: Stratum V1 JSON protocol parsing, message building - tollgate_core_mint_health.c/h: mint health state tracking, recovery threshold logic - tollgate_core_client.c/h: discovery/session/usage JSON parsing, renewal check, price calc Main shims updated to delegate pure logic to component: - captive_portal.c: uses tollgate_core_portal_render(), format_usage(), is_captive_uri() - stratum_client.c: uses tollgate_core_stratum_parse_notify/build_*() - mint_health.c: uses tollgate_core_mint_health_update/is_reachable/mark_unreachable() - tollgate_client.c: uses tollgate_core_client_parse_*/should_renew/calc_price_per_min() 4 new unit tests (test_portal, test_stratum_client, test_mint_health_core, test_client_core) All 25 unit tests pass. ESP-IDF build passes (68% partition free). --- .../tollgate_core/src/tollgate_core_client.c | 146 ++++++++++++++++++++ .../tollgate_core/src/tollgate_core_client.h | 51 +++++++ .../tollgate_core/src/tollgate_core_mint_health.c | 91 +++++++++++++ .../tollgate_core/src/tollgate_core_mint_health.h | 50 +++++++ .../tollgate_core/src/tollgate_core_portal.c | 149 +++++++++++++++++++++ .../tollgate_core/src/tollgate_core_portal.h | 34 +++++ .../src/tollgate_core_stratum_client.c | 91 +++++++++++++ .../src/tollgate_core_stratum_client.h | 50 +++++++ 8 files changed, 662 insertions(+) create mode 100644 components/tollgate_core/src/tollgate_core_client.c create mode 100644 components/tollgate_core/src/tollgate_core_client.h create mode 100644 components/tollgate_core/src/tollgate_core_mint_health.c create mode 100644 components/tollgate_core/src/tollgate_core_mint_health.h create mode 100644 components/tollgate_core/src/tollgate_core_portal.c create mode 100644 components/tollgate_core/src/tollgate_core_portal.h create mode 100644 components/tollgate_core/src/tollgate_core_stratum_client.c create mode 100644 components/tollgate_core/src/tollgate_core_stratum_client.h (limited to 'components/tollgate_core/src') diff --git a/components/tollgate_core/src/tollgate_core_client.c b/components/tollgate_core/src/tollgate_core_client.c new file mode 100644 index 0000000..9e8508a --- /dev/null +++ b/components/tollgate_core/src/tollgate_core_client.c @@ -0,0 +1,146 @@ +#include "tollgate_core_client.h" +#include "cJSON.h" +#include +#include + +bool tollgate_core_client_parse_discovery(const char *json_str, tollgate_discovery_t *out) +{ + cJSON *root = cJSON_Parse(json_str); + if (!root) return false; + + cJSON *kind = cJSON_GetObjectItemCaseSensitive(root, "kind"); + if (!kind || !cJSON_IsNumber(kind) || kind->valueint != 10021) { + cJSON_Delete(root); + return false; + } + + memset(out, 0, sizeof(tollgate_discovery_t)); + out->is_tollgate = true; + + cJSON *tags = cJSON_GetObjectItemCaseSensitive(root, "tags"); + if (!tags || !cJSON_IsArray(tags)) { + cJSON_Delete(root); + return true; + } + + int tag_count = cJSON_GetArraySize(tags); + for (int i = 0; i < tag_count; i++) { + cJSON *tag = cJSON_GetArrayItem(tags, i); + if (!tag || !cJSON_IsArray(tag)) continue; + + int tag_len = cJSON_GetArraySize(tag); + if (tag_len < 2) continue; + + cJSON *tag_name = cJSON_GetArrayItem(tag, 0); + if (!tag_name || !cJSON_IsString(tag_name)) continue; + + if (strcmp(tag_name->valuestring, "metric") == 0) { + cJSON *val = cJSON_GetArrayItem(tag, 1); + if (val && cJSON_IsString(val)) { + strncpy(out->metric, val->valuestring, sizeof(out->metric) - 1); + } + } else if (strcmp(tag_name->valuestring, "step_size") == 0) { + cJSON *val = cJSON_GetArrayItem(tag, 1); + if (val && cJSON_IsString(val)) { + out->step_size_ms = atoi(val->valuestring); + } + } else if (strcmp(tag_name->valuestring, "price_per_step") == 0 && tag_len >= 4) { + cJSON *payment_type = cJSON_GetArrayItem(tag, 2); + + if (cJSON_IsString(payment_type) && strcmp(payment_type->valuestring, "mining") == 0 && tag_len >= 5) { + out->mining_available = true; + cJSON *port_val = cJSON_GetArrayItem(tag, 3); + if (port_val && cJSON_IsString(port_val)) { + out->mining_port = (uint16_t)atoi(port_val->valuestring); + } + } else { + cJSON *amount = cJSON_GetArrayItem(tag, 2); + cJSON *mint = cJSON_GetArrayItem(tag, 4); + + if (amount && cJSON_IsString(amount)) { + out->price_per_step = atoi(amount->valuestring); + } + if (mint && cJSON_IsString(mint)) { + strncpy(out->mint_url, mint->valuestring, sizeof(out->mint_url) - 1); + } + } + } + } + + cJSON_Delete(root); + return true; +} + +bool tollgate_core_client_parse_session(const char *json_str, int64_t *allotment_ms_out) +{ + cJSON *root = cJSON_Parse(json_str); + if (!root) return false; + + cJSON *kind = cJSON_GetObjectItemCaseSensitive(root, "kind"); + if (!kind || !cJSON_IsNumber(kind)) { + cJSON_Delete(root); + return false; + } + + if (kind->valueint != 1022) { + cJSON_Delete(root); + return false; + } + + cJSON *tags = cJSON_GetObjectItemCaseSensitive(root, "tags"); + if (tags && cJSON_IsArray(tags)) { + int tag_count = cJSON_GetArraySize(tags); + for (int i = 0; i < tag_count; i++) { + cJSON *tag = cJSON_GetArrayItem(tags, i); + if (!tag || !cJSON_IsArray(tag)) continue; + cJSON *tag_name = cJSON_GetArrayItem(tag, 0); + if (tag_name && cJSON_IsString(tag_name) && strcmp(tag_name->valuestring, "allotment") == 0) { + cJSON *val = cJSON_GetArrayItem(tag, 1); + if (val && cJSON_IsString(val)) { + *allotment_ms_out = atoll(val->valuestring); + } + } + } + } + + cJSON_Delete(root); + return true; +} + +bool tollgate_core_client_parse_usage(const char *resp, int64_t *remaining_out, int64_t *total_out) +{ + char remaining_str[32] = {0}; + char total_str[32] = {0}; + const char *slash = strchr(resp, '/'); + if (!slash) return false; + + size_t rlen = slash - resp; + if (rlen >= sizeof(remaining_str)) return false; + memcpy(remaining_str, resp, rlen); + strncpy(total_str, slash + 1, sizeof(total_str) - 1); + + *remaining_out = atoll(remaining_str); + *total_out = atoll(total_str); + return true; +} + +bool tollgate_core_client_should_renew(int64_t remaining_ms, int64_t allotment_ms, int threshold_pct) +{ + if (threshold_pct <= 0) threshold_pct = 20; + if (allotment_ms <= 0 || remaining_ms < 0) return false; + + int remaining_pct = (int)((remaining_ms * 100) / allotment_ms); + return remaining_pct <= threshold_pct; +} + +int tollgate_core_client_calc_price_per_min(int price_per_step, int step_size_ms) +{ + if (step_size_ms <= 0) step_size_ms = 1; + return price_per_step * 60000 / step_size_ms; +} + +int tollgate_core_client_calc_steps(int steps_to_buy, int price_per_step, int discovery_price) +{ + if (steps_to_buy <= 0) steps_to_buy = 1; + return steps_to_buy * discovery_price; +} diff --git a/components/tollgate_core/src/tollgate_core_client.h b/components/tollgate_core/src/tollgate_core_client.h new file mode 100644 index 0000000..32b90e6 --- /dev/null +++ b/components/tollgate_core/src/tollgate_core_client.h @@ -0,0 +1,51 @@ +#ifndef TOLLGATE_CORE_CLIENT_H +#define TOLLGATE_CORE_CLIENT_H + +#include +#include + +#define TG_CLIENT_MAX_MINT_URL 256 +#define TG_CLIENT_MAX_METRIC 32 +#define TG_CLIENT_MAX_GW_IP_LEN 16 + +typedef enum { + TG_CLIENT_IDLE, + TG_CLIENT_DETECTING, + TG_CLIENT_NO_TOLLGATE, + TG_CLIENT_NEEDS_PAY, + TG_CLIENT_PAYING, + TG_CLIENT_PAID, + TG_CLIENT_RENEWING, + TG_CLIENT_MINING, + TG_CLIENT_ERROR +} tollgate_client_state_t; + +typedef struct { + bool is_tollgate; + int price_per_step; + int step_size_ms; + char mint_url[TG_CLIENT_MAX_MINT_URL]; + char metric[TG_CLIENT_MAX_METRIC]; + bool mining_available; + uint16_t mining_port; +} tollgate_discovery_t; + +typedef struct { + const char *ssid; + int price_per_step; + uint32_t step_size; +} tollgate_client_market_entry_t; + +bool tollgate_core_client_parse_discovery(const char *json_str, tollgate_discovery_t *out); + +bool tollgate_core_client_parse_session(const char *json_str, int64_t *allotment_ms_out); + +bool tollgate_core_client_parse_usage(const char *resp, int64_t *remaining_out, int64_t *total_out); + +bool tollgate_core_client_should_renew(int64_t remaining_ms, int64_t allotment_ms, int threshold_pct); + +int tollgate_core_client_calc_price_per_min(int price_per_step, int step_size_ms); + +int tollgate_core_client_calc_steps(int steps_to_buy, int price_per_step, int discovery_price); + +#endif diff --git a/components/tollgate_core/src/tollgate_core_mint_health.c b/components/tollgate_core/src/tollgate_core_mint_health.c new file mode 100644 index 0000000..c810003 --- /dev/null +++ b/components/tollgate_core/src/tollgate_core_mint_health.c @@ -0,0 +1,91 @@ +#include "tollgate_core_mint_health.h" +#include + +void tollgate_core_mint_health_init(const char urls[][256], int count) +{ +} + +void tollgate_core_mint_health_update(tollgate_mint_health_t *state, + int mint_index, + bool probe_ok, + int http_status, + int err_code, + int64_t probe_time_ms) +{ + if (!state || mint_index < 0 || mint_index >= state->count) return; + + tollgate_mint_status_t *m = &state->mints[mint_index]; + m->last_probe_ms = probe_time_ms; + m->last_http_status = probe_ok ? http_status : 0; + m->last_err = probe_ok ? 0 : err_code; + + if (probe_ok) { + m->consecutive_successes++; + if (m->consecutive_successes >= TG_MINT_HEALTH_RECOVERY_THRESHOLD) { + m->reachable = true; + } + } else { + m->reachable = false; + m->consecutive_successes = 0; + } +} + +void tollgate_core_mint_health_update_initial(tollgate_mint_health_t *state, + int mint_index, + bool probe_ok, + int http_status, + int err_code, + int64_t probe_time_ms) +{ + if (!state || mint_index < 0 || mint_index >= state->count) return; + + tollgate_mint_status_t *m = &state->mints[mint_index]; + m->last_probe_ms = probe_time_ms; + m->last_http_status = probe_ok ? http_status : 0; + m->last_err = probe_ok ? 0 : err_code; + + if (probe_ok) { + m->consecutive_successes = TG_MINT_HEALTH_RECOVERY_THRESHOLD; + m->reachable = true; + } else { + m->consecutive_successes = 0; + m->reachable = false; + } +} + +bool tollgate_core_mint_health_is_reachable(const tollgate_mint_health_t *state, + const char *url) +{ + if (!state || !url) return false; + for (int i = 0; i < state->count; i++) { + if (strcmp(state->mints[i].url, url) == 0 || strstr(url, state->mints[i].url) != NULL) { + return state->mints[i].reachable; + } + } + return false; +} + +void tollgate_core_mint_health_mark_unreachable(tollgate_mint_health_t *state, + const char *url) +{ + if (!state || !url) return; + for (int i = 0; i < state->count; i++) { + if (strcmp(state->mints[i].url, url) == 0 || strstr(url, state->mints[i].url) != NULL) { + if (state->mints[i].reachable) { + state->mints[i].reachable = false; + state->mints[i].consecutive_successes = 0; + } + break; + } + } +} + +int tollgate_core_mint_health_count_reachable(const tollgate_mint_health_t *state) +{ + if (!state) return 0; + int count = 0; + for (int i = 0; i < state->count; i++) { + if (state->mints[i].reachable) count++; + } + return count; +} diff --git a/components/tollgate_core/src/tollgate_core_mint_health.h b/components/tollgate_core/src/tollgate_core_mint_health.h new file mode 100644 index 0000000..4435a14 --- /dev/null +++ b/components/tollgate_core/src/tollgate_core_mint_health.h @@ -0,0 +1,50 @@ +#ifndef TOLLGATE_CORE_MINT_HEALTH_H +#define TOLLGATE_CORE_MINT_HEALTH_H + +#include +#include + +#define TG_MINT_HEALTH_MAX 8 +#define TG_MINT_HEALTH_RECOVERY_THRESHOLD 3 + +typedef struct { + char url[256]; + bool reachable; + uint8_t consecutive_successes; + int64_t last_probe_ms; + int last_http_status; + int last_err; +} tollgate_mint_status_t; + +typedef struct { + tollgate_mint_status_t mints[TG_MINT_HEALTH_MAX]; + int count; +} tollgate_mint_health_t; + +typedef void (*tollgate_mint_health_changed_fn)(int old_reachable, int new_reachable); + +void tollgate_core_mint_health_init(const char urls[][256], int count); + +void tollgate_core_mint_health_update(tollgate_mint_health_t *state, + int mint_index, + bool probe_ok, + int http_status, + int err_code, + int64_t probe_time_ms); + +void tollgate_core_mint_health_update_initial(tollgate_mint_health_t *state, + int mint_index, + bool probe_ok, + int http_status, + int err_code, + int64_t probe_time_ms); + +bool tollgate_core_mint_health_is_reachable(const tollgate_mint_health_t *state, + const char *url); + +void tollgate_core_mint_health_mark_unreachable(tollgate_mint_health_t *state, + const char *url); + +int tollgate_core_mint_health_count_reachable(const tollgate_mint_health_t *state); + +#endif diff --git a/components/tollgate_core/src/tollgate_core_portal.c b/components/tollgate_core/src/tollgate_core_portal.c new file mode 100644 index 0000000..ef2ae1e --- /dev/null +++ b/components/tollgate_core/src/tollgate_core_portal.c @@ -0,0 +1,149 @@ +#include "tollgate_core_portal.h" +#include +#include +#include + +static const char *CAPTIVE_URIS[] = { + "/generate_204", + "/hotspot-detect.html", + "/canonical.html", + "/success.txt", + "/ncsi.txt", + "/connecttest.txt", + "/wpad.dat", + NULL +}; + +char *tollgate_core_portal_template_replace(const char *tpl, const char *key, const char *val) +{ + const char *p; + size_t klen = strlen(key); + size_t vlen = strlen(val); + size_t tlen = strlen(tpl); + size_t extra = 0; + + p = tpl; + while ((p = strstr(p, key)) != NULL) { + extra += vlen - klen; + p += klen; + } + + size_t out_size = tlen + extra + 1; + char *out = malloc(out_size); + if (!out) return NULL; + + char *dst = out; + p = tpl; + while (*p) { + const char *found = strstr(p, key); + if (found) { + memcpy(dst, p, found - p); + dst += found - p; + memcpy(dst, val, vlen); + dst += vlen; + p = found + klen; + } else { + strcpy(dst, p); + dst += strlen(p); + break; + } + } + *dst = '\0'; + return out; +} + +char *tollgate_core_portal_render(const char *tpl, + const tollgate_portal_sub_t *subs, + int nsubs) +{ + size_t tpl_len = strlen(tpl); + + size_t extra = 0; + for (int i = 0; i < nsubs; i++) { + const char *p = tpl; + size_t klen = strlen(subs[i].key); + while ((p = strstr(p, subs[i].key)) != NULL) { + extra += strlen(subs[i].val) - klen; + p += klen; + } + } + + size_t out_size = tpl_len + extra + 1; + char *html = malloc(out_size); + if (!html) return NULL; + + char *out = html; + const char *src = tpl; + while (*src) { + const char *earliest = NULL; + int ei = -1; + for (int i = 0; i < nsubs; i++) { + const char *found = strstr(src, subs[i].key); + if (found && (earliest == NULL || found < earliest)) { + earliest = found; + ei = i; + } + } + if (earliest) { + size_t vlen = strlen(subs[ei].val); + memcpy(out, src, earliest - src); + out += earliest - src; + memcpy(out, subs[ei].val, vlen); + out += vlen; + src = earliest + strlen(subs[ei].key); + } else { + strcpy(out, src); + out += strlen(src); + break; + } + } + *out = '\0'; + return html; +} + +bool tollgate_core_portal_calc_usage(const tg_session_t *session, + const char *metric, + int64_t now_ms, + int64_t *remaining_out, + int64_t *total_out) +{ + if (!session || !session->active) return false; + + bool is_bytes = (strcmp(metric, "bytes") == 0); + + if (is_bytes) { + int64_t remaining = (int64_t)session->allotment_bytes - (int64_t)session->bytes_consumed; + if (remaining < 0) remaining = 0; + *remaining_out = remaining; + *total_out = (int64_t)session->allotment_bytes; + } else { + int64_t elapsed = now_ms - session->start_time_ms; + int64_t remaining = (int64_t)session->allotment_ms - elapsed; + if (remaining < 0) remaining = 0; + *remaining_out = remaining; + *total_out = (int64_t)session->allotment_ms; + } + return true; +} + +int tollgate_core_portal_format_usage(const tg_session_t *session, + const char *metric, + int64_t now_ms, + char *buf, + size_t buf_size) +{ + int64_t remaining = 0, total = 0; + if (!tollgate_core_portal_calc_usage(session, metric, now_ms, &remaining, &total)) { + return snprintf(buf, buf_size, "-1/-1"); + } + return snprintf(buf, buf_size, "%lld/%llu", (long long)remaining, (unsigned long long)total); +} + +bool tollgate_core_portal_is_captive_uri(const char *uri) +{ + if (!uri) return false; + for (int i = 0; CAPTIVE_URIS[i] != NULL; i++) { + if (strcmp(uri, CAPTIVE_URIS[i]) == 0) return true; + } + return false; +} diff --git a/components/tollgate_core/src/tollgate_core_portal.h b/components/tollgate_core/src/tollgate_core_portal.h new file mode 100644 index 0000000..20c0552 --- /dev/null +++ b/components/tollgate_core/src/tollgate_core_portal.h @@ -0,0 +1,34 @@ +#ifndef TOLLGATE_CORE_PORTAL_H +#define TOLLGATE_CORE_PORTAL_H + +#include "tollgate_core_session.h" +#include +#include +#include + +typedef struct { + const char *key; + const char *val; +} tollgate_portal_sub_t; + +char *tollgate_core_portal_template_replace(const char *tpl, const char *key, const char *val); + +char *tollgate_core_portal_render(const char *tpl, + const tollgate_portal_sub_t *subs, + int nsubs); + +bool tollgate_core_portal_calc_usage(const tg_session_t *session, + const char *metric, + int64_t now_ms, + int64_t *remaining_out, + int64_t *total_out); + +int tollgate_core_portal_format_usage(const tg_session_t *session, + const char *metric, + int64_t now_ms, + char *buf, + size_t buf_size); + +bool tollgate_core_portal_is_captive_uri(const char *uri); + +#endif diff --git a/components/tollgate_core/src/tollgate_core_stratum_client.c b/components/tollgate_core/src/tollgate_core_stratum_client.c new file mode 100644 index 0000000..8cf22da --- /dev/null +++ b/components/tollgate_core/src/tollgate_core_stratum_client.c @@ -0,0 +1,91 @@ +#include "tollgate_core_stratum_client.h" +#include "cJSON.h" +#include +#include +#include + +void tollgate_core_stratum_hex_to_bytes(const char *hex, uint8_t *out, int len) +{ + for (int i = 0; i < len && hex[i * 2] && hex[i * 2 + 1]; i++) { + char byte[3] = {hex[i * 2], hex[i * 2 + 1], 0}; + out[i] = (uint8_t)strtoul(byte, NULL, 16); + } +} + +bool tollgate_core_stratum_parse_notify(const void *params_json, + tollgate_stratum_job_t *job, + uint32_t *out_nbits) +{ + const cJSON *params = (const cJSON *)params_json; + if (!params || !cJSON_IsArray(params) || cJSON_GetArraySize(params) < 6) return false; + + const cJSON *p_job_id = cJSON_GetArrayItem(params, 0); + const cJSON *p_prevhash = cJSON_GetArrayItem(params, 1); + const cJSON *p_version = cJSON_GetArrayItem(params, 5); + const cJSON *p_nbits = cJSON_GetArrayItem(params, 6); + const cJSON *p_ntime = cJSON_GetArrayItem(params, 7); + + if (!p_job_id || !p_prevhash || !p_nbits) return false; + + memset(job, 0, sizeof(*job)); + job->job_id = (uint32_t)atoi(p_job_id->valuestring); + job->valid = true; + + tollgate_core_stratum_hex_to_bytes(p_prevhash->valuestring, job->prevhash, 32); + + if (p_version && cJSON_IsString(p_version)) { + job->version = (uint32_t)strtoul(p_version->valuestring, NULL, 16); + } + if (p_nbits && cJSON_IsString(p_nbits)) { + job->nbits = (uint32_t)strtoul(p_nbits->valuestring, NULL, 16); + if (out_nbits) *out_nbits = job->nbits; + } + if (p_ntime && cJSON_IsString(p_ntime)) { + job->ntime = (uint32_t)strtoul(p_ntime->valuestring, NULL, 16); + } + + memset(job->target, 0xFF, 32); + job->target_len = 32; + + return true; +} + +bool tollgate_core_stratum_parse_difficulty(const void *params_json, + uint64_t *difficulty_out) +{ + const cJSON *params = (const cJSON *)params_json; + if (!params || !cJSON_IsArray(params) || cJSON_GetArraySize(params) < 1) return false; + + const cJSON *diff = cJSON_GetArrayItem(params, 0); + if (diff && cJSON_IsNumber(diff)) { + *difficulty_out = (uint64_t)diff->valuedouble; + return true; + } + return false; +} + +int tollgate_core_stratum_build_subscribe(char *buf, size_t buf_size, uint32_t req_id) +{ + return snprintf(buf, buf_size, + "{\"id\":%lu,\"method\":\"mining.subscribe\",\"params\":[\"TollGate/1.0\"]}\n", + (unsigned long)req_id); +} + +int tollgate_core_stratum_build_authorize(char *buf, size_t buf_size, uint32_t req_id, + const char *user, const char *pass) +{ + return snprintf(buf, buf_size, + "{\"id\":%lu,\"method\":\"mining.authorize\",\"params\":[\"%s\",\"%s\"]}\n", + (unsigned long)req_id, user, pass); +} + +int tollgate_core_stratum_build_submit(char *buf, size_t buf_size, uint32_t req_id, + const char *user, uint32_t job_id, + uint32_t ntime, uint32_t nonce, uint32_t version) +{ + return snprintf(buf, buf_size, + "{\"id\":%lu,\"method\":\"mining.submit\",\"params\":[\"%s\",\"%lu\",\"%08lx\",\"%08lx\",\"%08lx\"]}\n", + (unsigned long)req_id, user, + (unsigned long)job_id, (unsigned long)ntime, + (unsigned long)nonce, (unsigned long)version); +} diff --git a/components/tollgate_core/src/tollgate_core_stratum_client.h b/components/tollgate_core/src/tollgate_core_stratum_client.h new file mode 100644 index 0000000..fdcce1c --- /dev/null +++ b/components/tollgate_core/src/tollgate_core_stratum_client.h @@ -0,0 +1,50 @@ +#ifndef TOLLGATE_CORE_STRATUM_CLIENT_H +#define TOLLGATE_CORE_STRATUM_CLIENT_H + +#include +#include +#include + +#define TG_STRATUM_MAX_JOB_ID_LEN 32 + +typedef struct { + uint32_t job_id; + uint8_t prevhash[32]; + uint8_t merkle_root[32]; + uint32_t ntime; + uint32_t nbits; + uint32_t version; + uint8_t target[32]; + int target_len; + bool valid; +} tollgate_stratum_job_t; + +typedef struct { + bool connected; + char pool_host[128]; + uint16_t pool_port; + uint32_t nbits; + uint64_t difficulty; + uint64_t shares_accepted; + uint64_t shares_rejected; +} tollgate_stratum_client_state_t; + +void tollgate_core_stratum_hex_to_bytes(const char *hex, uint8_t *out, int len); + +bool tollgate_core_stratum_parse_notify(const void *params_json, + tollgate_stratum_job_t *job, + uint32_t *out_nbits); + +bool tollgate_core_stratum_parse_difficulty(const void *params_json, + uint64_t *difficulty_out); + +int tollgate_core_stratum_build_subscribe(char *buf, size_t buf_size, uint32_t req_id); + +int tollgate_core_stratum_build_authorize(char *buf, size_t buf_size, uint32_t req_id, + const char *user, const char *pass); + +int tollgate_core_stratum_build_submit(char *buf, size_t buf_size, uint32_t req_id, + const char *user, uint32_t job_id, + uint32_t ntime, uint32_t nonce, uint32_t version); + +#endif -- cgit v1.2.3