#include "config.h" #include #include #include #include #include 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); }