Files
cpu-miner/config.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);
}