Merge pull request #336 from eandersson/fallback

Add stratum fallback support
This commit is contained in:
Erik Olof Gunnar Andersson 2024-10-05 22:29:59 +02:00 committed by GitHub
commit 3d15c25a07
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 383 additions and 200 deletions

View File

@ -75,12 +75,12 @@ void STRATUM_V1_free_mining_notify(mining_notify *params);
int STRATUM_V1_authenticate(int socket, const char *username, const char *pass);
void STRATUM_V1_configure_version_rolling(int socket, uint32_t * version_mask);
int STRATUM_V1_configure_version_rolling(int socket, uint32_t * version_mask);
int STRATUM_V1_suggest_difficulty(int socket, uint32_t difficulty);
void STRATUM_V1_submit_share(int socket, const char *username, const char *jobid,
const char *extranonce_2, const uint32_t ntime, const uint32_t nonce,
const uint32_t version);
int STRATUM_V1_submit_share(int socket, const char *username, const char *jobid,
const char *extranonce_2, const uint32_t ntime, const uint32_t nonce,
const uint32_t version);
#endif // STRATUM_API_H

View File

@ -90,7 +90,7 @@ char * STRATUM_V1_receive_jsonrpc_line(int sockfd)
memset(recv_buffer, 0, BUFFER_SIZE);
nbytes = recv(sockfd, recv_buffer, BUFFER_SIZE - 1, 0);
if (nbytes == -1) {
ESP_LOGI(TAG, "Error: recv");
ESP_LOGI(TAG, "Error: recv (errno %d: %s)", errno, strerror(errno));
if (json_rpc_buffer) {
free(json_rpc_buffer);
json_rpc_buffer=0;
@ -314,9 +314,8 @@ int STRATUM_V1_subscribe(int socket, char * model)
const char *version = app_desc->version;
sprintf(subscribe_msg, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": [\"bitaxe/%s/%s\"]}\n", send_uid++, model, version);
debug_stratum_tx(subscribe_msg);
write(socket, subscribe_msg, strlen(subscribe_msg));
return 1;
return write(socket, subscribe_msg, strlen(subscribe_msg));
}
int STRATUM_V1_suggest_difficulty(int socket, uint32_t difficulty)
@ -324,9 +323,8 @@ int STRATUM_V1_suggest_difficulty(int socket, uint32_t difficulty)
char difficulty_msg[BUFFER_SIZE];
sprintf(difficulty_msg, "{\"id\": %d, \"method\": \"mining.suggest_difficulty\", \"params\": [%ld]}\n", send_uid++, difficulty);
debug_stratum_tx(difficulty_msg);
write(socket, difficulty_msg, strlen(difficulty_msg));
return 1;
return write(socket, difficulty_msg, strlen(difficulty_msg));
}
int STRATUM_V1_authenticate(int socket, const char * username, const char * pass)
@ -336,9 +334,7 @@ int STRATUM_V1_authenticate(int socket, const char * username, const char * pass
pass);
debug_stratum_tx(authorize_msg);
write(socket, authorize_msg, strlen(authorize_msg));
return 1;
return write(socket, authorize_msg, strlen(authorize_msg));
}
/// @param socket Socket to write to
@ -347,7 +343,7 @@ int STRATUM_V1_authenticate(int socket, const char * username, const char * pass
/// @param ntime The hex-encoded time value use in the block header.
/// @param extranonce_2 The hex-encoded value of extra nonce 2.
/// @param nonce The hex-encoded nonce value to use in the block header.
void STRATUM_V1_submit_share(int socket, const char * username, const char * jobid, const char * extranonce_2, const uint32_t ntime,
int STRATUM_V1_submit_share(int socket, const char * username, const char * jobid, const char * extranonce_2, const uint32_t ntime,
const uint32_t nonce, const uint32_t version)
{
char submit_msg[BUFFER_SIZE];
@ -355,10 +351,11 @@ void STRATUM_V1_submit_share(int socket, const char * username, const char * job
"{\"id\": %d, \"method\": \"mining.submit\", \"params\": [\"%s\", \"%s\", \"%s\", \"%08lx\", \"%08lx\", \"%08lx\"]}\n",
send_uid++, username, jobid, extranonce_2, ntime, nonce, version);
debug_stratum_tx(submit_msg);
write(socket, submit_msg, strlen(submit_msg));
return write(socket, submit_msg, strlen(submit_msg));
}
void STRATUM_V1_configure_version_rolling(int socket, uint32_t * version_mask)
int STRATUM_V1_configure_version_rolling(int socket, uint32_t * version_mask)
{
char configure_msg[BUFFER_SIZE * 2];
sprintf(configure_msg,
@ -366,9 +363,8 @@ void STRATUM_V1_configure_version_rolling(int socket, uint32_t * version_mask)
"\"ffffffff\"}]}\n",
send_uid++);
debug_stratum_tx(configure_msg);
write(socket, configure_msg, strlen(configure_msg));
return;
return write(socket, configure_msg, strlen(configure_msg));
}
static void debug_stratum_tx(const char * msg)

View File

@ -29,6 +29,19 @@ menu "Stratum Configuration"
help
The stratum server port to connect to.
config FALLBACK_STRATUM_URL
string "Fallback Stratum Address"
default "solo.ckpool.org"
help
The example will connect to this Stratum pool address if the primary fails.
config FALLBACK_STRATUM_PORT
int "Fallback Stratum Port"
range 0 65535
default 3333
help
The stratum server port to connect to if the primary fails.
config STRATUM_USER
string "Stratum username"
default "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa.bitaxe"
@ -41,6 +54,18 @@ menu "Stratum Configuration"
help
Stratum password to use with pool
config FALLBACK_STRATUM_USER
string "Fallback Stratum username"
default "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa.bitaxe"
help
Fallback Stratum user to use with pool
config FALLBACK_STRATUM_PW
string "Fallback Stratum password"
default "x"
help
Fallback Stratum password to use with pool
config STRATUM_DIFFICULTY
int "Stratum default difficulty"
range 0 4294967296

View File

@ -15,6 +15,7 @@
#include "work_queue.h"
#define STRATUM_USER CONFIG_STRATUM_USER
#define FALLBACK_STRATUM_USER CONFIG_FALLBACK_STRATUM_USER
#define HISTORY_LENGTH 100
#define DIFF_STRING_SIZE 10
@ -69,9 +70,11 @@ typedef struct
char ssid[32];
char wifi_status[20];
char * pool_url;
char * fallback_pool_url;
uint16_t pool_port;
uint16_t fallback_pool_port;
bool is_using_fallback;
uint16_t overheat_mode;
uint32_t lastClockSync;
} SystemModule;

View File

@ -16,10 +16,10 @@
<div class="field grid p-fluid">
<label htmlFor="wifiPass" class="col-12 mb-2 md:col-2 md:mb-0">WiFi Password:</label>
<div class="col-12 md:col-10 p-input-icon-right">
<i *ngIf="form.get('wifiPass')?.dirty" class="pi"
[ngClass]="{'pi-eye': !showWifiPassword, 'pi-eye-slash': showWifiPassword}"
<i *ngIf="form.get('wifiPass')?.dirty" class="pi"
[ngClass]="{'pi-eye': !showWifiPassword, 'pi-eye-slash': showWifiPassword}"
(click)="toggleWifiPasswordVisibility()" style="cursor: pointer;"></i>
<input pInputText id="wifiPass" formControlName="wifiPass"
<input pInputText id="wifiPass" formControlName="wifiPass"
[type]="showWifiPassword ? 'text' : 'password'"
placeholder="Enter WiFi password" />
</div>
@ -34,8 +34,6 @@
</div>
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="stratumPort" class="col-12 mb-2 md:col-2 md:mb-0">Stratum Port:</label>
<div class="col-12 md:col-10">
@ -51,16 +49,42 @@
<div class="field grid p-fluid">
<label htmlFor="stratumPassword" class="col-12 mb-2 md:col-2 md:mb-0">Stratum Password:</label>
<div class="col-12 md:col-10 p-input-icon-right">
<i *ngIf="form.get('stratumPassword')?.dirty" class="pi"
[ngClass]="{'pi-eye': !showStratumPassword, 'pi-eye-slash': showStratumPassword}"
<i *ngIf="form.get('stratumPassword')?.dirty" class="pi"
[ngClass]="{'pi-eye': !showStratumPassword, 'pi-eye-slash': showStratumPassword}"
(click)="toggleStratumPasswordVisibility()" style="cursor: pointer;"></i>
<input pInputText id="stratumPassword" formControlName="stratumPassword"
<input pInputText id="stratumPassword" formControlName="stratumPassword"
[type]="showStratumPassword ? 'text' : 'password'"
placeholder="Enter stratum password" />
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="stratumURL" class="col-12 mb-2 md:col-2 md:mb-0">Fallback Stratum URL:</label>
<div class="col-12 md:col-10">
<input pInputText id="fallbackStratumURL" type="text" formControlName="fallbackStratumURL"
formControlName="fallbackStratumURL" />
<div>
<small>Do not include 'stratum+tcp://' or port.</small>
</div>
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="fallbackStratumPort" class="col-12 mb-2 md:col-2 md:mb-0">Fallback Stratum Port:</label>
<div class="col-12 md:col-10">
<input pInputText id="fallbackStratumPort" formControlName="fallbackStratumPort" type="number" />
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="fallbackStratumUser" class="col-12 mb-2 md:col-2 md:mb-0">Fallback Stratum User:</label>
<div class="col-12 md:col-10">
<input pInputText id="fallbackStratumUser" formControlName="fallbackStratumUser" type="text" />
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="fallbackStratumPassword" class="col-12 mb-2 md:col-2 md:mb-0">Fallback Stratum Password:</label>
<div class="col-12 md:col-10">
<input pInputText id="fallbackStratumPassword" formControlName="fallbackStratumPassword" type="password" />
</div>
</div>
<ng-container *ngIf="!devToolsOpen && ASICModel == eASICModel.BM1366">
@ -199,4 +223,4 @@
</form>
</ng-container>
</ng-container>

View File

@ -146,8 +146,19 @@ export class EditComponent implements OnInit {
Validators.min(0),
Validators.max(65353)
]],
fallbackStratumURL: [info.fallbackStratumURL, [
Validators.pattern(/^(?!.*stratum\+tcp:\/\/).*$/),
]],
fallbackStratumPort: [info.fallbackStratumPort, [
Validators.required,
Validators.pattern(/^[^:]*$/),
Validators.min(0),
Validators.max(65353)
]],
stratumUser: [info.stratumUser, [Validators.required]],
stratumPassword: ['*****', [Validators.required]],
fallbackStratumUser: [info.fallbackStratumUser, [Validators.required]],
fallbackStratumPassword: ['password', [Validators.required]],
hostname: [info.hostname, [Validators.required]],
ssid: [info.ssid, [Validators.required]],
wifiPass: ['*****'],

View File

@ -226,7 +226,18 @@
<td>User:</td>
<td style="word-break: break-all;">{{info.stratumUser}}</td>
</tr>
<tr>
<td>Fallback URL:</td>
<td style="word-break: break-all;">{{info.fallbackStratumURL}}</td>
</tr>
<tr>
<td>Fallback Port:</td>
<td style="word-break: break-all;">{{info.fallbackStratumPort}}</td>
</tr>
<tr>
<td>Fallback User:</td>
<td style="word-break: break-all;">{{info.fallbackStratumUser}}</td>
</tr>
</table>
</div>
</div>

View File

@ -45,7 +45,10 @@ export class SystemService {
ASICModel: eASICModel.BM1366,
stratumURL: "public-pool.io",
stratumPort: 21496,
fallbackStratumURL: "test.public-pool.io",
fallbackStratumPort: 21497,
stratumUser: "bc1q99n3pu025yyu0jlywpmwzalyhm36tg5u37w20d.bitaxe-U1",
fallbackStratumUser: "bc1q99n3pu025yyu0jlywpmwzalyhm36tg5u37w20d.bitaxe-U1",
frequency: 485,
version: "2.0",
boardVersion: "204",

View File

@ -26,7 +26,10 @@ export interface ISystemInfo {
ASICModel: eASICModel,
stratumURL: string,
stratumPort: number,
fallbackStratumURL: string,
fallbackStratumPort: number,
stratumUser: string,
fallbackStratumUser: string,
frequency: number,
version: string,
boardVersion: string,

View File

@ -273,15 +273,27 @@ static esp_err_t PATCH_update_settings(httpd_req_t * req)
if ((item = cJSON_GetObjectItem(root, "stratumURL")) != NULL) {
nvs_config_set_string(NVS_CONFIG_STRATUM_URL, item->valuestring);
}
if ((item = cJSON_GetObjectItem(root, "fallbackStratumURL")) != NULL) {
nvs_config_set_string(NVS_CONFIG_FALLBACK_STRATUM_URL, item->valuestring);
}
if ((item = cJSON_GetObjectItem(root, "stratumUser")) != NULL) {
nvs_config_set_string(NVS_CONFIG_STRATUM_USER, item->valuestring);
}
if ((item = cJSON_GetObjectItem(root, "stratumPassword")) != NULL) {
nvs_config_set_string(NVS_CONFIG_STRATUM_PASS, item->valuestring);
}
if ((item = cJSON_GetObjectItem(root, "fallbackStratumUser")) != NULL) {
nvs_config_set_string(NVS_CONFIG_FALLBACK_STRATUM_USER, item->valuestring);
}
if ((item = cJSON_GetObjectItem(root, "fallbackStratumPassword")) != NULL) {
nvs_config_set_string(NVS_CONFIG_FALLBACK_STRATUM_PASS, item->valuestring);
}
if ((item = cJSON_GetObjectItem(root, "stratumPort")) != NULL) {
nvs_config_set_u16(NVS_CONFIG_STRATUM_PORT, item->valueint);
}
if ((item = cJSON_GetObjectItem(root, "fallbackStratumPort")) != NULL) {
nvs_config_set_u16(NVS_CONFIG_FALLBACK_STRATUM_PORT, item->valueint);
}
if ((item = cJSON_GetObjectItem(root, "ssid")) != NULL) {
nvs_config_set_string(NVS_CONFIG_WIFI_SSID, item->valuestring);
}
@ -372,7 +384,9 @@ static esp_err_t GET_system_info(httpd_req_t * req)
uint8_t mac[6];
char formattedMac[18];
char * stratumURL = nvs_config_get_string(NVS_CONFIG_STRATUM_URL, CONFIG_STRATUM_URL);
char * fallbackStratumURL = nvs_config_get_string(NVS_CONFIG_FALLBACK_STRATUM_URL, CONFIG_FALLBACK_STRATUM_URL);
char * stratumUser = nvs_config_get_string(NVS_CONFIG_STRATUM_USER, CONFIG_STRATUM_USER);
char * fallbackStratumUser = nvs_config_get_string(NVS_CONFIG_FALLBACK_STRATUM_USER, CONFIG_FALLBACK_STRATUM_USER);
char * board_version = nvs_config_get_string(NVS_CONFIG_BOARD_VERSION, "unknown");
esp_wifi_get_mac(WIFI_IF_STA, mac);
@ -422,8 +436,11 @@ static esp_err_t GET_system_info(httpd_req_t * req)
cJSON_AddNumberToObject(root, "smallCoreCount", small_core_count);
cJSON_AddStringToObject(root, "ASICModel", GLOBAL_STATE->asic_model_str);
cJSON_AddStringToObject(root, "stratumURL", stratumURL);
cJSON_AddStringToObject(root, "fallbackStratumURL", fallbackStratumURL);
cJSON_AddNumberToObject(root, "stratumPort", nvs_config_get_u16(NVS_CONFIG_STRATUM_PORT, CONFIG_STRATUM_PORT));
cJSON_AddNumberToObject(root, "fallbackStratumPort", nvs_config_get_u16(NVS_CONFIG_FALLBACK_STRATUM_PORT, CONFIG_FALLBACK_STRATUM_PORT));
cJSON_AddStringToObject(root, "stratumUser", stratumUser);
cJSON_AddStringToObject(root, "fallbackStratumUser", fallbackStratumUser);
cJSON_AddStringToObject(root, "version", esp_app_get_description()->version);
cJSON_AddStringToObject(root, "boardVersion", board_version);
@ -442,7 +459,9 @@ static esp_err_t GET_system_info(httpd_req_t * req)
free(ssid);
free(hostname);
free(stratumURL);
free(fallbackStratumURL);
free(stratumUser);
free(fallbackStratumUser);
free(board_version);
const char * sys_info = cJSON_Print(root);

View File

@ -10,8 +10,12 @@
#define NVS_CONFIG_HOSTNAME "hostname"
#define NVS_CONFIG_STRATUM_URL "stratumurl"
#define NVS_CONFIG_STRATUM_PORT "stratumport"
#define NVS_CONFIG_FALLBACK_STRATUM_URL "fbstratumurl"
#define NVS_CONFIG_FALLBACK_STRATUM_PORT "fbstratumport"
#define NVS_CONFIG_STRATUM_USER "stratumuser"
#define NVS_CONFIG_STRATUM_PASS "stratumpass"
#define NVS_CONFIG_FALLBACK_STRATUM_USER "fbstratumuser"
#define NVS_CONFIG_FALLBACK_STRATUM_PASS "fbstratumpass"
#define NVS_CONFIG_ASIC_FREQ "asicfrequency"
#define NVS_CONFIG_ASIC_VOLTAGE "asicvoltage"
#define NVS_CONFIG_ASIC_MODEL "asicmodel"

View File

@ -76,9 +76,14 @@ static void _init_system(GlobalState * GLOBAL_STATE)
// set the pool url
module->pool_url = nvs_config_get_string(NVS_CONFIG_STRATUM_URL, CONFIG_STRATUM_URL);
module->fallback_pool_url = nvs_config_get_string(NVS_CONFIG_FALLBACK_STRATUM_URL, CONFIG_FALLBACK_STRATUM_URL);
//set the pool port
module->pool_port = nvs_config_get_u16(NVS_CONFIG_STRATUM_PORT, CONFIG_STRATUM_PORT);
module->fallback_pool_port = nvs_config_get_u16(NVS_CONFIG_FALLBACK_STRATUM_PORT, CONFIG_FALLBACK_STRATUM_PORT);
// set fallback to false.
module->is_using_fallback = false;
// Initialize overheat_mode
module->overheat_mode = nvs_config_get_u16(NVS_CONFIG_OVERHEAT_MODE, 0);

View File

@ -6,6 +6,8 @@
#include "esp_log.h"
#include "nvs_config.h"
#include "utils.h"
#include "stratum_task.h"
#include <lwip/tcpip.h>
static const char *TAG = "asic_result";
@ -17,7 +19,6 @@ void ASIC_result_task(void *pvParameters)
while (1)
{
task_result *asic_result = (*GLOBAL_STATE->ASIC_functions.receive_result_fn)(GLOBAL_STATE);
if (asic_result == NULL)
@ -44,8 +45,7 @@ void ASIC_result_task(void *pvParameters)
if (nonce_diff > GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->pool_diff)
{
STRATUM_V1_submit_share(
int ret = STRATUM_V1_submit_share(
GLOBAL_STATE->sock,
user,
GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->jobid,
@ -54,6 +54,10 @@ void ASIC_result_task(void *pvParameters)
asic_result->nonce,
asic_result->rolled_version ^ GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->version);
if (ret < 0) {
ESP_LOGI(TAG, "Unable to write share to socket. Closing connection. Ret: %d (errno %d: %s)", ret, errno, strerror(errno));
stratum_close_connection(GLOBAL_STATE);
}
}
SYSTEM_notify_found_nonce(GLOBAL_STATE, nonce_diff, job_id);

View File

@ -5,6 +5,7 @@
#include "system.h"
#include "global_state.h"
#include "lwip/dns.h"
#include <lwip/tcpip.h>
#include "nvs_config.h"
#include "stratum_task.h"
#include "work_queue.h"
@ -15,31 +16,23 @@
#define PORT CONFIG_STRATUM_PORT
#define STRATUM_URL CONFIG_STRATUM_URL
#define FALLBACK_PORT CONFIG_FALLBACK_STRATUM_PORT
#define FALLBACK_STRATUM_URL CONFIG_FALLBACK_STRATUM_URL
#define STRATUM_PW CONFIG_STRATUM_PW
#define FALLBACK_STRATUM_PW CONFIG_FALLBACK_STRATUM_PW
#define STRATUM_DIFFICULTY CONFIG_STRATUM_DIFFICULTY
#define BASE_DELAY_MS 5000
#define MAX_RETRY_ATTEMPTS 5
#define MAX_RETRY_ATTEMPTS 3
#define MAX_CRITICAL_RETRY_ATTEMPTS 5
static const char * TAG = "stratum_task";
static ip_addr_t ip_Addr;
static bool bDNSFound = false;
static bool bDNSInvalid = false;
static StratumApiV1Message stratum_api_v1_message = {};
static SystemTaskModule SYSTEM_TASK_MODULE = {.stratum_difficulty = 8192};
void dns_found_cb(const char * name, const ip_addr_t * ipaddr, void * callback_arg)
{
if (ipaddr != NULL){
ip4_addr_t ip4addr = ipaddr->u_addr.ip4; // Obtener la estructura ip4_addr_t
ESP_LOGI(TAG, "IP found : %d.%d.%d.%d", ip4_addr1(&ip4addr), ip4_addr2(&ip4addr), ip4_addr3(&ip4addr), ip4_addr4(&ip4addr));
ip_Addr = *ipaddr;
} else {
bDNSInvalid = true;
}
bDNSFound = true;
}
static const char * primary_stratum_url;
static uint16_t primary_stratum_port;
bool is_wifi_connected() {
wifi_ap_record_t ap_info;
@ -63,177 +56,258 @@ void cleanQueue(GlobalState * GLOBAL_STATE) {
pthread_mutex_unlock(&GLOBAL_STATE->valid_jobs_lock);
}
void stratum_close_connection(GlobalState * GLOBAL_STATE)
{
if (GLOBAL_STATE->sock < 0) {
ESP_LOGE(TAG, "Socket already shutdown, not shutting down again..");
return;
}
ESP_LOGE(TAG, "Shutting down socket and restarting...");
shutdown(GLOBAL_STATE->sock, SHUT_RDWR);
close(GLOBAL_STATE->sock);
cleanQueue(GLOBAL_STATE);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
void stratum_primary_heartbeat(void * pvParameters)
{
GlobalState * GLOBAL_STATE = (GlobalState *) pvParameters;
ESP_LOGI(TAG, "Starting heartbeat thread for primary endpoint: %s", primary_stratum_url);
vTaskDelay(10000 / portTICK_PERIOD_MS);
int addr_family = AF_INET;
int ip_protocol = IPPROTO_IP;
while (1)
{
if (GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback == false) {
vTaskDelay(10000 / portTICK_PERIOD_MS);
continue;
}
char host_ip[INET_ADDRSTRLEN];
ESP_LOGD(TAG, "Running Heartbeat on: %s!", primary_stratum_url);
if (!is_wifi_connected()) {
ESP_LOGD(TAG, "Heartbeat. Failed WiFi check!");
vTaskDelay(10000 / portTICK_PERIOD_MS);
continue;
}
struct hostent *primary_dns_addr = gethostbyname(primary_stratum_url);
if (primary_dns_addr == NULL) {
ESP_LOGD(TAG, "Heartbeat. Failed DNS check for: %s!", primary_stratum_url);
vTaskDelay(60000 / portTICK_PERIOD_MS);
continue;
}
inet_ntop(AF_INET, (void *)primary_dns_addr->h_addr_list[0], host_ip, sizeof(host_ip));
struct sockaddr_in dest_addr;
dest_addr.sin_addr.s_addr = inet_addr(host_ip);
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(primary_stratum_port);
int sock = socket(addr_family, SOCK_STREAM, ip_protocol);
if (sock < 0) {
ESP_LOGD(TAG, "Heartbeat. Failed socket create check!");
vTaskDelay(60000 / portTICK_PERIOD_MS);
close(sock);
continue;
}
int err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6));
if (err != 0)
{
ESP_LOGD(TAG, "Heartbeat. Failed connect check: %s:%d (errno %d: %s)", host_ip, primary_stratum_port, errno, strerror(errno));
close(sock);
vTaskDelay(60000 / portTICK_PERIOD_MS);
continue;
}
shutdown(sock, SHUT_RDWR);
close(sock);
if (GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback) {
ESP_LOGI(TAG, "Heartbeat successful and in fallback mode. Switching back to primary.");
GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback = false;
stratum_close_connection(GLOBAL_STATE);
vTaskDelay(60000 / portTICK_PERIOD_MS);
continue;
}
vTaskDelay(60000 / portTICK_PERIOD_MS);
}
}
void stratum_task(void * pvParameters)
{
GlobalState * GLOBAL_STATE = (GlobalState *) pvParameters;
STRATUM_V1_initialize_buffer();
char host_ip[20];
int addr_family = 0;
int ip_protocol = 0;
int retry_attempts = 0;
int delay_ms = BASE_DELAY_MS;
char *stratum_url = GLOBAL_STATE->SYSTEM_MODULE.pool_url;
primary_stratum_url = GLOBAL_STATE->SYSTEM_MODULE.pool_url;
primary_stratum_port = GLOBAL_STATE->SYSTEM_MODULE.pool_port;
char * stratum_url = GLOBAL_STATE->SYSTEM_MODULE.pool_url;
uint16_t port = GLOBAL_STATE->SYSTEM_MODULE.pool_port;
STRATUM_V1_initialize_buffer();
char host_ip[20];
int addr_family = AF_INET;
int ip_protocol = IPPROTO_IP;
int retry_attempts = 0;
int retry_critical_attempts = 0;
struct timeval timeout = {};
timeout.tv_sec = 5;
timeout.tv_usec = 0;
xTaskCreate(stratum_primary_heartbeat, "stratum primary heartbeat", 4096, pvParameters, 1, NULL);
ESP_LOGI(TAG, "Trying to get IP for URL: %s", stratum_url);
while (1) {
//clear flags used by the dns callback, dns_found_cb()
bDNSFound = false;
bDNSInvalid = false;
// check to see if the STRATUM_URL is an ip address already
if (inet_pton(AF_INET, stratum_url, &ip_Addr) == 1) {
bDNSFound = true;
if (!is_wifi_connected()) {
ESP_LOGI(TAG, "WiFi disconnected, attempting to reconnect...");
esp_wifi_connect();
vTaskDelay(10000 / portTICK_PERIOD_MS);
continue;
}
else
{
ESP_LOGI(TAG, "Get IP for URL: %s", stratum_url);
dns_gethostbyname(stratum_url, &ip_Addr, dns_found_cb, NULL);
while (!bDNSFound);
if (bDNSInvalid) {
ESP_LOGE(TAG, "DNS lookup failed for URL: %s", stratum_url);
//set ip_Addr to 0.0.0.0 so that connect() will fail
IP_ADDR4(&ip_Addr, 0, 0, 0, 0);
if (retry_attempts >= MAX_RETRY_ATTEMPTS)
{
if (GLOBAL_STATE->SYSTEM_MODULE.fallback_pool_url == NULL || GLOBAL_STATE->SYSTEM_MODULE.fallback_pool_url[0] == '\0') {
ESP_LOGI(TAG, "Unable to switch to fallback. No url configured. (retries: %d)...", retry_attempts);
GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback = false;
retry_attempts = 0;
continue;
}
GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback = !GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback;
ESP_LOGI(TAG, "Switching target due to too many failures (retries: %d)...", retry_attempts);
retry_attempts = 0;
}
// make IP address string from ip_Addr
snprintf(host_ip, sizeof(host_ip), "%d.%d.%d.%d", ip4_addr1(&ip_Addr.u_addr.ip4), ip4_addr2(&ip_Addr.u_addr.ip4),
ip4_addr3(&ip_Addr.u_addr.ip4), ip4_addr4(&ip_Addr.u_addr.ip4));
stratum_url = GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback ? GLOBAL_STATE->SYSTEM_MODULE.fallback_pool_url : GLOBAL_STATE->SYSTEM_MODULE.pool_url;
port = GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback ? GLOBAL_STATE->SYSTEM_MODULE.fallback_pool_port : GLOBAL_STATE->SYSTEM_MODULE.pool_port;
struct hostent *dns_addr = gethostbyname(stratum_url);
if (dns_addr == NULL) {
retry_attempts++;
vTaskDelay(1000 / portTICK_PERIOD_MS);
continue;
}
inet_ntop(AF_INET, (void *)dns_addr->h_addr_list[0], host_ip, sizeof(host_ip));
ESP_LOGI(TAG, "Connecting to: stratum+tcp://%s:%d (%s)", stratum_url, port, host_ip);
struct sockaddr_in dest_addr;
dest_addr.sin_addr.s_addr = inet_addr(host_ip);
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port);
GLOBAL_STATE->sock = socket(addr_family, SOCK_STREAM, ip_protocol);
if (GLOBAL_STATE->sock < 0) {
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
if (++retry_critical_attempts > MAX_CRITICAL_RETRY_ATTEMPTS) {
ESP_LOGE(TAG, "Max retry attempts reached, restarting...");
esp_restart();
}
vTaskDelay(5000 / portTICK_PERIOD_MS);
continue;
}
retry_critical_attempts = 0;
ESP_LOGI(TAG, "Socket created, connecting to %s:%d", host_ip, port);
int err = connect(GLOBAL_STATE->sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6));
if (err != 0)
{
retry_attempts++;
ESP_LOGE(TAG, "Socket unable to connect to %s:%d (errno %d: %s)", stratum_url, port, errno, strerror(errno));
// close the socket
shutdown(GLOBAL_STATE->sock, SHUT_RDWR);
close(GLOBAL_STATE->sock);
// instead of restarting, retry this every 5 seconds
vTaskDelay(5000 / portTICK_PERIOD_MS);
continue;
}
retry_attempts = 0;
if (setsockopt(GLOBAL_STATE->sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) != 0) {
ESP_LOGE(TAG, "Fail to setsockopt SO_SNDTIMEO");
}
STRATUM_V1_reset_uid();
cleanQueue(GLOBAL_STATE);
///// Start Stratum Action
// mining.subscribe - ID: 1
STRATUM_V1_subscribe(GLOBAL_STATE->sock, GLOBAL_STATE->asic_model_str);
// mining.configure - ID: 2
STRATUM_V1_configure_version_rolling(GLOBAL_STATE->sock, &GLOBAL_STATE->version_mask);
char * username = GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback ? nvs_config_get_string(NVS_CONFIG_FALLBACK_STRATUM_USER, FALLBACK_STRATUM_USER) : nvs_config_get_string(NVS_CONFIG_STRATUM_USER, STRATUM_USER);
char * password = GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback ? nvs_config_get_string(NVS_CONFIG_FALLBACK_STRATUM_PASS, FALLBACK_STRATUM_PW) : nvs_config_get_string(NVS_CONFIG_STRATUM_PASS, STRATUM_PW);
//mining.authorize - ID: 3
STRATUM_V1_authenticate(GLOBAL_STATE->sock, username, password);
free(password);
free(username);
//mining.suggest_difficulty - ID: 4
STRATUM_V1_suggest_difficulty(GLOBAL_STATE->sock, STRATUM_DIFFICULTY);
while (1) {
if (!is_wifi_connected()) {
ESP_LOGI(TAG, "WiFi disconnected, attempting to reconnect...");
esp_wifi_connect();
vTaskDelay(10000 / portTICK_PERIOD_MS);
//delay_ms *= 2; // Increase delay exponentially
continue;
char * line = STRATUM_V1_receive_jsonrpc_line(GLOBAL_STATE->sock);
if (!line) {
ESP_LOGE(TAG, "Failed to receive JSON-RPC line, reconnecting...");
stratum_close_connection(GLOBAL_STATE);
break;
}
ESP_LOGI(TAG, "rx: %s", line); // debug incoming stratum messages
STRATUM_V1_parse(&stratum_api_v1_message, line);
free(line);
struct sockaddr_in dest_addr;
dest_addr.sin_addr.s_addr = inet_addr(host_ip);
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port);
addr_family = AF_INET;
ip_protocol = IPPROTO_IP;
GLOBAL_STATE->sock = socket(addr_family, SOCK_STREAM, ip_protocol);
if (GLOBAL_STATE->sock < 0) {
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
if (++retry_attempts > MAX_RETRY_ATTEMPTS) {
ESP_LOGE(TAG, "Max retry attempts reached, restarting...");
esp_restart();
if (stratum_api_v1_message.method == MINING_NOTIFY) {
SYSTEM_notify_new_ntime(GLOBAL_STATE, stratum_api_v1_message.mining_notification->ntime);
if (stratum_api_v1_message.should_abandon_work &&
(GLOBAL_STATE->stratum_queue.count > 0 || GLOBAL_STATE->ASIC_jobs_queue.count > 0)) {
cleanQueue(GLOBAL_STATE);
}
vTaskDelay(5000 / portTICK_PERIOD_MS);
continue;
}
ESP_LOGI(TAG, "Socket created, connecting to %s:%d", host_ip, port);
retry_attempts = 0;
int err = connect(GLOBAL_STATE->sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6));
if (err != 0)
{
ESP_LOGE(TAG, "Socket unable to connect to %s:%d (errno %d)", stratum_url, port, errno);
// close the socket
shutdown(GLOBAL_STATE->sock, SHUT_RDWR);
close(GLOBAL_STATE->sock);
// instead of restarting, retry this every 5 seconds
vTaskDelay(5000 / portTICK_PERIOD_MS);
continue;
}
STRATUM_V1_reset_uid();
cleanQueue(GLOBAL_STATE);
///// Start Stratum Action
// mining.subscribe - ID: 1
STRATUM_V1_subscribe(GLOBAL_STATE->sock, GLOBAL_STATE->asic_model_str);
// mining.configure - ID: 2
STRATUM_V1_configure_version_rolling(GLOBAL_STATE->sock, &GLOBAL_STATE->version_mask);
char * username = nvs_config_get_string(NVS_CONFIG_STRATUM_USER, STRATUM_USER);
char * password = nvs_config_get_string(NVS_CONFIG_STRATUM_PASS, STRATUM_PW);
//mining.authorize - ID: 3
STRATUM_V1_authenticate(GLOBAL_STATE->sock, username, password);
free(password);
free(username);
//mining.suggest_difficulty - ID: 4
STRATUM_V1_suggest_difficulty(GLOBAL_STATE->sock, STRATUM_DIFFICULTY);
while (1) {
char * line = STRATUM_V1_receive_jsonrpc_line(GLOBAL_STATE->sock);
if (!line) {
ESP_LOGE(TAG, "Failed to receive JSON-RPC line, reconnecting...");
shutdown(GLOBAL_STATE->sock, SHUT_RDWR);
close(GLOBAL_STATE->sock);
vTaskDelay(1000 / portTICK_PERIOD_MS); // Delay before attempting to reconnect
break;
if (GLOBAL_STATE->stratum_queue.count == QUEUE_SIZE) {
mining_notify * next_notify_json_str = (mining_notify *) queue_dequeue(&GLOBAL_STATE->stratum_queue);
STRATUM_V1_free_mining_notify(next_notify_json_str);
}
ESP_LOGI(TAG, "rx: %s", line); // debug incoming stratum messages
STRATUM_V1_parse(&stratum_api_v1_message, line);
free(line);
if (stratum_api_v1_message.method == MINING_NOTIFY) {
SYSTEM_notify_new_ntime(GLOBAL_STATE, stratum_api_v1_message.mining_notification->ntime);
if (stratum_api_v1_message.should_abandon_work &&
(GLOBAL_STATE->stratum_queue.count > 0 || GLOBAL_STATE->ASIC_jobs_queue.count > 0)) {
cleanQueue(GLOBAL_STATE);
}
if (GLOBAL_STATE->stratum_queue.count == QUEUE_SIZE) {
mining_notify * next_notify_json_str = (mining_notify *) queue_dequeue(&GLOBAL_STATE->stratum_queue);
STRATUM_V1_free_mining_notify(next_notify_json_str);
}
stratum_api_v1_message.mining_notification->difficulty = SYSTEM_TASK_MODULE.stratum_difficulty;
queue_enqueue(&GLOBAL_STATE->stratum_queue, stratum_api_v1_message.mining_notification);
} else if (stratum_api_v1_message.method == MINING_SET_DIFFICULTY) {
if (stratum_api_v1_message.new_difficulty != SYSTEM_TASK_MODULE.stratum_difficulty) {
SYSTEM_TASK_MODULE.stratum_difficulty = stratum_api_v1_message.new_difficulty;
ESP_LOGI(TAG, "Set stratum difficulty: %ld", SYSTEM_TASK_MODULE.stratum_difficulty);
}
} else if (stratum_api_v1_message.method == MINING_SET_VERSION_MASK ||
stratum_api_v1_message.method == STRATUM_RESULT_VERSION_MASK) {
// 1fffe000
ESP_LOGI(TAG, "Set version mask: %08lx", stratum_api_v1_message.version_mask);
GLOBAL_STATE->version_mask = stratum_api_v1_message.version_mask;
GLOBAL_STATE->new_stratum_version_rolling_msg = true;
} else if (stratum_api_v1_message.method == STRATUM_RESULT_SUBSCRIBE) {
GLOBAL_STATE->extranonce_str = stratum_api_v1_message.extranonce_str;
GLOBAL_STATE->extranonce_2_len = stratum_api_v1_message.extranonce_2_len;
} else if (stratum_api_v1_message.method == CLIENT_RECONNECT) {
ESP_LOGE(TAG, "Pool requested client reconnect...");
shutdown(GLOBAL_STATE->sock, SHUT_RDWR);
close(GLOBAL_STATE->sock);
vTaskDelay(1000 / portTICK_PERIOD_MS); // Delay before attempting to reconnect
break;
} else if (stratum_api_v1_message.method == STRATUM_RESULT) {
if (stratum_api_v1_message.response_success) {
ESP_LOGI(TAG, "message result accepted");
SYSTEM_notify_accepted_share(GLOBAL_STATE);
} else {
ESP_LOGW(TAG, "message result rejected");
SYSTEM_notify_rejected_share(GLOBAL_STATE);
}
} else if (stratum_api_v1_message.method == STRATUM_RESULT_SETUP) {
if (stratum_api_v1_message.response_success) {
ESP_LOGI(TAG, "setup message accepted");
} else {
ESP_LOGE(TAG, "setup message rejected");
}
stratum_api_v1_message.mining_notification->difficulty = SYSTEM_TASK_MODULE.stratum_difficulty;
queue_enqueue(&GLOBAL_STATE->stratum_queue, stratum_api_v1_message.mining_notification);
} else if (stratum_api_v1_message.method == MINING_SET_DIFFICULTY) {
if (stratum_api_v1_message.new_difficulty != SYSTEM_TASK_MODULE.stratum_difficulty) {
SYSTEM_TASK_MODULE.stratum_difficulty = stratum_api_v1_message.new_difficulty;
ESP_LOGI(TAG, "Set stratum difficulty: %ld", SYSTEM_TASK_MODULE.stratum_difficulty);
}
} else if (stratum_api_v1_message.method == MINING_SET_VERSION_MASK ||
stratum_api_v1_message.method == STRATUM_RESULT_VERSION_MASK) {
// 1fffe000
ESP_LOGI(TAG, "Set version mask: %08lx", stratum_api_v1_message.version_mask);
GLOBAL_STATE->version_mask = stratum_api_v1_message.version_mask;
GLOBAL_STATE->new_stratum_version_rolling_msg = true;
} else if (stratum_api_v1_message.method == STRATUM_RESULT_SUBSCRIBE) {
GLOBAL_STATE->extranonce_str = stratum_api_v1_message.extranonce_str;
GLOBAL_STATE->extranonce_2_len = stratum_api_v1_message.extranonce_2_len;
} else if (stratum_api_v1_message.method == CLIENT_RECONNECT) {
ESP_LOGE(TAG, "Pool requested client reconnect...");
stratum_close_connection(GLOBAL_STATE);
break;
} else if (stratum_api_v1_message.method == STRATUM_RESULT) {
if (stratum_api_v1_message.response_success) {
ESP_LOGI(TAG, "message result accepted");
SYSTEM_notify_accepted_share(GLOBAL_STATE);
} else {
ESP_LOGW(TAG, "message result rejected");
SYSTEM_notify_rejected_share(GLOBAL_STATE);
}
} else if (stratum_api_v1_message.method == STRATUM_RESULT_SETUP) {
if (stratum_api_v1_message.response_success) {
ESP_LOGI(TAG, "setup message accepted");
} else {
ESP_LOGE(TAG, "setup message rejected");
}
}
if (GLOBAL_STATE->sock != -1) {
ESP_LOGE(TAG, "Shutting down socket and restarting...");
shutdown(GLOBAL_STATE->sock, 0);
close(GLOBAL_STATE->sock);
}
}
}

View File

@ -7,5 +7,6 @@ typedef struct
} SystemTaskModule;
void stratum_task(void *pvParameters);
void stratum_close_connection(GlobalState * GLOBAL_STATE);
#endif