249 lines
6.8 KiB
C
249 lines
6.8 KiB
C
|
|
#include "config.h"
|
||
|
|
|
||
|
|
#include <ctype.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
#include <unistd.h>
|
||
|
|
|
||
|
|
static char *trim(char *s) {
|
||
|
|
char *end;
|
||
|
|
|
||
|
|
while (*s && isspace((unsigned char)*s)) {
|
||
|
|
++s;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (*s == '\0') {
|
||
|
|
return s;
|
||
|
|
}
|
||
|
|
|
||
|
|
end = s + strlen(s) - 1;
|
||
|
|
while (end > s && isspace((unsigned char)*end)) {
|
||
|
|
--end;
|
||
|
|
}
|
||
|
|
end[1] = '\0';
|
||
|
|
return s;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int hex_is_valid_even(const char *s) {
|
||
|
|
size_t i;
|
||
|
|
size_t n = strlen(s);
|
||
|
|
|
||
|
|
if (n == 0 || (n % 2) != 0) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (i = 0; i < n; ++i) {
|
||
|
|
if (isxdigit((unsigned char)s[i]) == 0) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
void config_set_defaults(MinerConfig *cfg) {
|
||
|
|
long ncpu;
|
||
|
|
|
||
|
|
memset(cfg, 0, sizeof(*cfg));
|
||
|
|
|
||
|
|
snprintf(cfg->rpc_user, sizeof(cfg->rpc_user), "%s", "regtest");
|
||
|
|
snprintf(cfg->rpc_password, sizeof(cfg->rpc_password), "%s", "regtest");
|
||
|
|
snprintf(cfg->rpc_host, sizeof(cfg->rpc_host), "%s", "127.0.0.1");
|
||
|
|
cfg->rpc_port = 18443;
|
||
|
|
|
||
|
|
snprintf(cfg->wallet_address, sizeof(cfg->wallet_address), "%s", "bcrt1qn9ewln06n3xmc64278nj8m4nyde7ddeuvsvhw6");
|
||
|
|
|
||
|
|
cfg->difficulty_factor = 0.01;
|
||
|
|
snprintf(cfg->nonce_mode, sizeof(cfg->nonce_mode), "%s", "incremental");
|
||
|
|
cfg->timestamp_update_interval = 30;
|
||
|
|
cfg->batch = 10000;
|
||
|
|
snprintf(cfg->coinbase_message, sizeof(cfg->coinbase_message), "%s", "/py-miner/");
|
||
|
|
snprintf(cfg->extranonce1, sizeof(cfg->extranonce1), "%s", "1234567890abcdef");
|
||
|
|
snprintf(cfg->extranonce2, sizeof(cfg->extranonce2), "%s", "12341234");
|
||
|
|
|
||
|
|
ncpu = sysconf(_SC_NPROCESSORS_ONLN);
|
||
|
|
cfg->num_processors = (ncpu > 0) ? (int)ncpu : 1;
|
||
|
|
|
||
|
|
cfg->check_interval = 20;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int set_string_value(char *dst, size_t cap, const char *value, const char *key) {
|
||
|
|
size_t n = strlen(value);
|
||
|
|
|
||
|
|
if (n >= cap) {
|
||
|
|
fprintf(stderr, "[config] %s troppo lungo\n", key);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
memcpy(dst, value, n + 1);
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int parse_line(MinerConfig *cfg, const char *key, const char *value) {
|
||
|
|
if (strcmp(key, "RPC_USER") == 0) {
|
||
|
|
return set_string_value(cfg->rpc_user, sizeof(cfg->rpc_user), value, key);
|
||
|
|
}
|
||
|
|
if (strcmp(key, "RPC_PASSWORD") == 0) {
|
||
|
|
return set_string_value(cfg->rpc_password, sizeof(cfg->rpc_password), value, key);
|
||
|
|
}
|
||
|
|
if (strcmp(key, "RPC_HOST") == 0) {
|
||
|
|
return set_string_value(cfg->rpc_host, sizeof(cfg->rpc_host), value, key);
|
||
|
|
}
|
||
|
|
if (strcmp(key, "RPC_PORT") == 0) {
|
||
|
|
cfg->rpc_port = atoi(value);
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
if (strcmp(key, "WALLET_ADDRESS") == 0) {
|
||
|
|
return set_string_value(cfg->wallet_address, sizeof(cfg->wallet_address), value, key);
|
||
|
|
}
|
||
|
|
if (strcmp(key, "DIFFICULTY_FACTOR") == 0) {
|
||
|
|
cfg->difficulty_factor = strtod(value, NULL);
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
if (strcmp(key, "NONCE_MODE") == 0) {
|
||
|
|
return set_string_value(cfg->nonce_mode, sizeof(cfg->nonce_mode), value, key);
|
||
|
|
}
|
||
|
|
if (strcmp(key, "TIMESTAMP_UPDATE_INTERVAL") == 0) {
|
||
|
|
cfg->timestamp_update_interval = atoi(value);
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
if (strcmp(key, "BATCH") == 0) {
|
||
|
|
long v = atol(value);
|
||
|
|
cfg->batch = (v > 0) ? (uint32_t)v : 0;
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
if (strcmp(key, "COINBASE_MESSAGE") == 0) {
|
||
|
|
return set_string_value(cfg->coinbase_message, sizeof(cfg->coinbase_message), value, key);
|
||
|
|
}
|
||
|
|
if (strcmp(key, "EXTRANONCE1") == 0) {
|
||
|
|
return set_string_value(cfg->extranonce1, sizeof(cfg->extranonce1), value, key);
|
||
|
|
}
|
||
|
|
if (strcmp(key, "EXTRANONCE2") == 0) {
|
||
|
|
return set_string_value(cfg->extranonce2, sizeof(cfg->extranonce2), value, key);
|
||
|
|
}
|
||
|
|
if (strcmp(key, "NUM_PROCESSORS") == 0) {
|
||
|
|
cfg->num_processors = atoi(value);
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
if (strcmp(key, "CHECK_INTERVAL") == 0) {
|
||
|
|
cfg->check_interval = atoi(value);
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
fprintf(stderr, "[config] chiave sconosciuta: %s\n", key);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool config_validate(const MinerConfig *cfg) {
|
||
|
|
if (cfg->rpc_port <= 0) {
|
||
|
|
fprintf(stderr, "[config] RPC_PORT deve essere > 0\n");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (cfg->batch == 0) {
|
||
|
|
fprintf(stderr, "[config] BATCH deve essere > 0\n");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (cfg->timestamp_update_interval < 0) {
|
||
|
|
fprintf(stderr, "[config] TIMESTAMP_UPDATE_INTERVAL deve essere >= 0\n");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (cfg->check_interval <= 0) {
|
||
|
|
fprintf(stderr, "[config] CHECK_INTERVAL deve essere > 0\n");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (strcmp(cfg->nonce_mode, "incremental") == 0 ||
|
||
|
|
strcmp(cfg->nonce_mode, "random") == 0 ||
|
||
|
|
strcmp(cfg->nonce_mode, "mixed") == 0) {
|
||
|
|
/* ok */
|
||
|
|
} else {
|
||
|
|
fprintf(stderr, "[config] NONCE_MODE non valido: %s\n", cfg->nonce_mode);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (hex_is_valid_even(cfg->extranonce1) == 0 || hex_is_valid_even(cfg->extranonce2) == 0) {
|
||
|
|
fprintf(stderr, "[config] EXTRANONCE1/EXTRANONCE2 devono essere hex con lunghezza pari\n");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (cfg->wallet_address[0] == '\0') {
|
||
|
|
fprintf(stderr, "[config] WALLET_ADDRESS mancante\n");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool config_load(const char *path, MinerConfig *cfg) {
|
||
|
|
FILE *fp;
|
||
|
|
char line[512];
|
||
|
|
|
||
|
|
config_set_defaults(cfg);
|
||
|
|
|
||
|
|
fp = fopen(path, "r");
|
||
|
|
if (fp == NULL) {
|
||
|
|
perror("[config] fopen");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
while (fgets(line, sizeof(line), fp) != NULL) {
|
||
|
|
char *eq;
|
||
|
|
char *key;
|
||
|
|
char *value;
|
||
|
|
char *comment;
|
||
|
|
size_t n;
|
||
|
|
|
||
|
|
comment = strchr(line, '#');
|
||
|
|
if (comment != NULL) {
|
||
|
|
*comment = '\0';
|
||
|
|
}
|
||
|
|
|
||
|
|
key = trim(line);
|
||
|
|
if (*key == '\0') {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
eq = strchr(key, '=');
|
||
|
|
if (eq == NULL) {
|
||
|
|
fprintf(stderr, "[config] riga non valida (manca '='): %s\n", key);
|
||
|
|
fclose(fp);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
*eq = '\0';
|
||
|
|
value = trim(eq + 1);
|
||
|
|
key = trim(key);
|
||
|
|
|
||
|
|
n = strlen(value);
|
||
|
|
if (n >= 2 && ((value[0] == '"' && value[n - 1] == '"') || (value[0] == '\'' && value[n - 1] == '\''))) {
|
||
|
|
value[n - 1] = '\0';
|
||
|
|
++value;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (parse_line(cfg, key, value) == 0) {
|
||
|
|
fclose(fp);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
fclose(fp);
|
||
|
|
|
||
|
|
if (cfg->num_processors <= 0) {
|
||
|
|
long ncpu = sysconf(_SC_NPROCESSORS_ONLN);
|
||
|
|
cfg->num_processors = (ncpu > 0) ? (int)ncpu : 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
return config_validate(cfg);
|
||
|
|
}
|
||
|
|
|
||
|
|
void config_print(const MinerConfig *cfg) {
|
||
|
|
printf("RPC: %s@%s:%d\n", cfg->rpc_user, cfg->rpc_host, cfg->rpc_port);
|
||
|
|
printf("Wallet: %s\n", cfg->wallet_address);
|
||
|
|
printf("Mining: mode=%s batch=%u diff_factor=%.8f\n", cfg->nonce_mode, cfg->batch, cfg->difficulty_factor);
|
||
|
|
printf("Workers: %d | check_interval=%d\n", cfg->num_processors, cfg->check_interval);
|
||
|
|
}
|