diff --git a/Makefile.am b/Makefile.am index ea8c9b7..f2bcc1a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,7 +19,7 @@ ccminer_SOURCES = elist.h miner.h compat.h \ compat/inttypes.h compat/stdbool.h compat/unistd.h \ compat/sys/time.h compat/getopt/getopt.h \ crc32.c hefty1.c \ - ccminer.cpp util.cpp bignum.cpp \ + ccminer.cpp pools.cpp util.cpp bignum.cpp \ api.cpp hashlog.cpp nvml.cpp stats.cpp sysinfos.cpp cuda.cpp \ heavy/heavy.cu \ heavy/cuda_blake512.cu heavy/cuda_blake512.h \ diff --git a/ccminer.cpp b/ccminer.cpp index 2129101..5ebd4dd 100644 --- a/ccminer.cpp +++ b/ccminer.cpp @@ -23,7 +23,6 @@ #include #include -#include #include #ifdef WIN32 @@ -177,10 +176,10 @@ static bool opt_background = false; bool opt_quiet = false; static int opt_retries = -1; static int opt_fail_pause = 30; -static int opt_time_limit = -1; -static time_t firstwork_time = 0; +int opt_time_limit = -1; +time_t firstwork_time = 0; int opt_timeout = 60; // curl -static int opt_scantime = 10; +int opt_scantime = 10; static json_t *opt_config; static const bool opt_time = true; static enum sha_algos opt_algo = ALGO_X11; @@ -226,9 +225,9 @@ bool conditional_pool_rotate = false; // current connection char *rpc_user = NULL; -static char *rpc_pass; +char *rpc_pass; char *rpc_url; -static char *short_url = NULL; +char *short_url = NULL; struct stratum_ctx stratum = { 0 }; pthread_mutex_t stratum_sock_lock; @@ -269,17 +268,6 @@ char *opt_api_allow = strdup("127.0.0.1"); /* 0.0.0.0 for all ips */ int opt_api_remote = 0; int opt_api_listen = 4068; /* 0 to disable */ -#ifdef HAVE_GETOPT_LONG -#include -#else -struct option { - const char *name; - int has_arg; - int *flag; - int val; -}; -#endif - static char const usage[] = "\ Usage: " PROGRAM_NAME " [OPTIONS]\n\ Options:\n\ @@ -381,7 +369,7 @@ static char const short_options[] = #endif "a:Bc:i:Dhp:Px:f:m:nqr:R:s:t:T:o:u:O:Vd:N:b:l:L:"; -static struct option const options[] = { +struct option options[] = { { "algo", 1, NULL, 'a' }, { "api-bind", 1, NULL, 'b' }, { "api-remote", 0, NULL, 1030 }, @@ -456,31 +444,18 @@ Scrypt specific options:\n\ --no-autotune disable auto-tuning of kernel launch parameters\n\ "; -#define CFG_NULL 0 -#define CFG_POOL 1 -struct opt_config_array { - int cat; - const char *name; // json key - const char *longname; // global opt name if different -} cfg_array_keys[] = { - { CFG_POOL, "url", NULL }, /* let this key first, increment pools */ - { CFG_POOL, "user", NULL }, - { CFG_POOL, "pass", NULL }, - { CFG_POOL, "userpass", NULL }, - { CFG_POOL, "name", "pool-name" }, - { CFG_POOL, "scantime", "pool-scantime" }, - { CFG_POOL, "max-diff", "pool-max-diff" }, - { CFG_POOL, "max-rate", "pool-max-rate" }, - { CFG_POOL, "removed", "pool-removed" }, - { CFG_POOL, "disabled", "pool-removed" }, // sample alias - { CFG_POOL, "time-limit", "pool-time-limit" }, - { CFG_NULL, NULL, NULL } -}; - struct work _ALIGN(64) g_work; volatile time_t g_work_time; pthread_mutex_t g_work_lock; +// get const array size (defined in ccminer.cpp) +int options_count() +{ + int n = 0; + while (options[n].name != NULL) + n++; + return n; +} #ifdef __linux /* Linux specific policy and affinity management */ #include @@ -1275,7 +1250,7 @@ static void *workio_thread(void *userdata) return NULL; } -static bool get_work(struct thr_info *thr, struct work *work) +bool get_work(struct thr_info *thr, struct work *work) { struct workio_cmd *wc; struct work *work_heap; @@ -2402,236 +2377,6 @@ pool_switched: goto wait_stratum_url; } -// store current credentials in pools container -void pool_set_creds(int pooln) -{ - struct pool_infos *p = &pools[pooln]; - - snprintf(p->url, sizeof(p->url), "%s", rpc_url); - snprintf(p->short_url, sizeof(p->short_url), "%s", short_url); - snprintf(p->user, sizeof(p->user), "%s", rpc_user); - snprintf(p->pass, sizeof(p->pass), "%s", rpc_pass); - - if (!(p->status & POOL_ST_DEFINED)) { - p->id = pooln; - p->status |= POOL_ST_DEFINED; - // init pool options as "unset" - // until cmdline is not fully parsed... - p->max_diff = -1.; - p->max_rate = -1.; - p->scantime = -1; - p->time_limit = -1; - - p->allow_mininginfo = allow_mininginfo; - p->allow_gbt = allow_gbt; - p->check_dups = check_dups; - - p->status |= POOL_ST_DEFINED; - } - - if (strlen(rpc_url)) { - if (!strncasecmp(rpc_url, "stratum", 7)) - p->type = POOL_STRATUM; - else /* if (!strncasecmp(rpc_url, "http", 4)) */ - p->type = POOL_GETWORK; // todo: or longpoll - p->status |= POOL_ST_VALID; - } -} - -// fill the unset pools options with cmdline ones -void pool_init_defaults() -{ - struct pool_infos *p; - for (int i=0; imax_diff <= -1.) p->max_diff = opt_max_diff; - if (p->max_rate <= -1.) p->max_rate = opt_max_rate; - if (p->scantime == -1) p->scantime = opt_scantime; - if (p->time_limit == -1) p->time_limit = opt_time_limit; - } -} - -// attributes only set by a json pools config -void pool_set_attr(int pooln, const char* key, char* arg) -{ - struct pool_infos *p = &pools[pooln]; - - if (!strcasecmp(key, "name")) { - snprintf(p->name, sizeof(p->name), "%s", arg); - return; - } - if (!strcasecmp(key, "scantime")) { - p->scantime = atoi(arg); - return; - } - if (!strcasecmp(key, "max-diff")) { - p->max_diff = atof(arg); - return; - } - if (!strcasecmp(key, "max-rate")) { - p->max_rate = atof(arg); - return; - } - if (!strcasecmp(key, "time-limit")) { - p->time_limit = atoi(arg); - return; - } - if (!strcasecmp(key, "removed")) { - int removed = atoi(arg); - if (removed) { - p->status |= POOL_ST_REMOVED; - } - return; - } -} - -// pool switching code -bool pool_switch(int pooln) -{ - int prevn = cur_pooln; - struct pool_infos *prev = &pools[cur_pooln]; - struct pool_infos* p = NULL; - - // save prev stratum connection infos (struct) - if (prev->type & POOL_STRATUM) { - // may not be the right moment to free, - // to check if required on submit... - stratum_free_job(&stratum); - prev->stratum = stratum; - } - - if (pooln < num_pools) { - cur_pooln = pooln; - p = &pools[cur_pooln]; - } else { - applog(LOG_ERR, "Switch to inexistant pool %d!", pooln); - return false; - } - - // save global attributes - prev->allow_mininginfo = allow_mininginfo; - prev->allow_gbt = allow_gbt; - prev->check_dups = check_dups; - - pthread_mutex_lock(&stratum_work_lock); - - free(rpc_user); rpc_user = strdup(p->user); - free(rpc_pass); rpc_pass = strdup(p->pass); - free(rpc_url); rpc_url = strdup(p->url); - - short_url = p->short_url; // just a pointer, no alloc - - opt_scantime = p->scantime; - opt_max_diff = p->max_diff; - opt_max_rate = p->max_rate; - opt_time_limit = p->time_limit; - - want_stratum = have_stratum = (p->type & POOL_STRATUM) != 0; - - pthread_mutex_unlock(&stratum_work_lock); - - if (prevn != cur_pooln) { - - pool_switch_count++; - g_work_time = 0; - g_work.data[0] = 0; - pool_is_switching = true; - stratum_need_reset = true; - // used to get the pool uptime - firstwork_time = time(NULL); - restart_threads(); - - // restore flags - allow_gbt = p->allow_gbt; - allow_mininginfo = p->allow_mininginfo; - check_dups = p->check_dups; - - if (want_stratum) { - - // temporary... until stratum code cleanup - stratum = p->stratum; - stratum.pooln = cur_pooln; - - // unlock the stratum thread - tq_push(thr_info[stratum_thr_id].q, strdup(rpc_url)); - applog(LOG_BLUE, "Switch to stratum pool %d: %s", cur_pooln, - strlen(p->name) ? p->name : p->short_url); - } else { - applog(LOG_BLUE, "Switch to pool %d: %s", cur_pooln, - strlen(p->name) ? p->name : p->short_url); - } - - // will unlock the longpoll thread on /LP url receive - want_longpoll = (p->type & POOL_LONGPOLL) || !(p->type & POOL_STRATUM); - if (want_longpoll) { - pthread_mutex_lock(&stratum_work_lock); - // will issue a lp_url request to unlock the longpoll thread - have_longpoll = false; - get_work(&thr_info[0], &g_work); - pthread_mutex_unlock(&stratum_work_lock); - } - - } - return true; -} - -// search available pool -int pool_get_first_valid(int startfrom) -{ - int next = 0; - struct pool_infos *p; - for (int i=0; istatus & POOL_ST_VALID)) - continue; - if (p->status & (POOL_ST_DISABLED | POOL_ST_REMOVED)) - continue; - next = pooln; - break; - } - return next; -} - -// switch to next available pool -bool pool_switch_next() -{ - if (num_pools > 1) { - int pooln = pool_get_first_valid(cur_pooln+1); - return pool_switch(pooln); - } else { - // no switch possible - if (!opt_quiet) - applog(LOG_DEBUG, "No other pools to try..."); - return false; - } -} - -// seturl from api remote -bool pool_switch_url(char *params) -{ - int prevn = cur_pooln, nextn; - parse_arg('o', params); - // cur_pooln modified by parse_arg('o'), get new pool num - nextn = cur_pooln; - // and to handle the "hot swap" from current one... - cur_pooln = prevn; - if (nextn == prevn) - return false; - return pool_switch(nextn); -} - -// debug stuff -void pool_dump_infos() -{ - struct pool_infos *p; - for (int i=0; ishort_url, p->user, p->scantime); - } -} - static void show_version_and_exit(void) { printf("%s v%s\n" @@ -3130,75 +2875,6 @@ void parse_arg(int key, char *arg) use_colors = false; } -/** - * Parse json config - */ -static bool parse_pool_array(json_t *obj) -{ - size_t idx; - json_t *p, *val; - - if (!json_is_array(obj)) - return false; - - // array of objects [ {}, {} ] - json_array_foreach(obj, idx, p) - { - if (!json_is_object(p)) - continue; - - for (int i = 0; i < ARRAY_SIZE(cfg_array_keys); i++) - { - int opt = -1; - char *s = NULL; - if (cfg_array_keys[i].cat != CFG_POOL) - continue; - - val = json_object_get(p, cfg_array_keys[i].name); - if (!val) - continue; - - for (int k = 0; k < ARRAY_SIZE(options); k++) - { - const char *alias = cfg_array_keys[i].longname; - if (alias && !strcasecmp(options[k].name, alias)) { - opt = k; - break; - } - if (!alias && !strcasecmp(options[k].name, cfg_array_keys[i].name)) { - opt = k; - break; - } - } - if (opt == -1) - continue; - - if (json_is_string(val)) { - s = strdup(json_string_value(val)); - if (!s) - continue; - - // applog(LOG_DEBUG, "pool key %s '%s'", options[opt].name, s); - parse_arg(options[opt].val, s); - free(s); - } else { - // numeric or bool - char buf[32] = { 0 }; - double d = 0.; - if (json_is_true(val)) d = 1.; - else if (json_is_integer(val)) - d = 1.0 * json_integer_value(val); - else if (json_is_real(val)) - d = json_real_value(val); - snprintf(buf, sizeof(buf)-1, "%f", d); - // applog(LOG_DEBUG, "pool key %s '%f'", options[opt].name, d); - parse_arg(options[opt].val, buf); - } - } - } - return true; -} - void parse_config(json_t* json_obj) { int i; diff --git a/ccminer.vcxproj b/ccminer.vcxproj index 235e36c..438675d 100644 --- a/ccminer.vcxproj +++ b/ccminer.vcxproj @@ -227,8 +227,7 @@ false Full - - + @@ -249,6 +248,8 @@ + + diff --git a/ccminer.vcxproj.filters b/ccminer.vcxproj.filters index 2569bd3..dd19768 100644 --- a/ccminer.vcxproj.filters +++ b/ccminer.vcxproj.filters @@ -111,6 +111,9 @@ Source Files + + Source Files + Source Files @@ -653,4 +656,4 @@ Ressources - \ No newline at end of file + diff --git a/miner.h b/miner.h index 47a8e9c..5b7a2d9 100644 --- a/miner.h +++ b/miner.h @@ -469,6 +469,18 @@ struct work_restart { char padding[128 - sizeof(uint32_t)]; }; +#ifdef HAVE_GETOPT_LONG +#include +#else +struct option { + const char *name; + int has_arg; + int *flag; + int val; +}; +#endif +extern int options_count(); + extern bool opt_benchmark; extern bool opt_debug; extern bool opt_quiet; @@ -680,12 +692,15 @@ extern struct pool_infos pools[MAX_POOLS]; extern int num_pools; extern volatile int cur_pooln; -int pool_get_first_valid(int startfrom); +void pool_init_defaults(void); void pool_set_creds(int pooln); void pool_set_attr(int pooln, const char* key, char* arg); bool pool_switch_url(char *params); bool pool_switch(int pooln); bool pool_switch_next(void); +int pool_get_first_valid(int startfrom); +bool parse_pool_array(json_t *obj); +void pool_dump_infos(void); json_t * json_rpc_call_pool(CURL *curl, struct pool_infos*, const char *req, bool lp_scan, bool lp, int *err); diff --git a/pools.cpp b/pools.cpp new file mode 100644 index 0000000..e3b09ed --- /dev/null +++ b/pools.cpp @@ -0,0 +1,357 @@ +/** + * Functions which handle multiple pools data + */ + +#include +#include +#include +#include + +#include "miner.h" +#include "compat.h" + +// to move in miner.h +extern bool allow_gbt; +extern bool allow_mininginfo; +extern bool check_dups; + +extern double opt_max_diff; +extern double opt_max_rate; +extern int opt_scantime; +extern int opt_time_limit; + +extern char* rpc_url; +extern char* rpc_user; +extern char* rpc_pass; +extern char* short_url; + +extern struct work _ALIGN(64) g_work; +extern struct stratum_ctx stratum; +extern pthread_mutex_t stratum_work_lock; +extern bool get_work(struct thr_info *thr, struct work *work); +extern bool stratum_need_reset; +extern time_t firstwork_time; + +extern volatile time_t g_work_time; +extern volatile int pool_switch_count; +extern volatile bool pool_is_switching; + +extern struct option options[]; + +#define CFG_NULL 0 +#define CFG_POOL 1 +struct opt_config_array { + int cat; + const char *name; // json key + const char *longname; // global opt name if different +} cfg_array_keys[] = { + { CFG_POOL, "url", NULL }, /* let this key first, increment pools */ + { CFG_POOL, "user", NULL }, + { CFG_POOL, "pass", NULL }, + { CFG_POOL, "userpass", NULL }, + { CFG_POOL, "name", "pool-name" }, + { CFG_POOL, "scantime", "pool-scantime" }, + { CFG_POOL, "max-diff", "pool-max-diff" }, + { CFG_POOL, "max-rate", "pool-max-rate" }, + { CFG_POOL, "removed", "pool-removed" }, + { CFG_POOL, "disabled", "pool-removed" }, // sample alias + { CFG_POOL, "time-limit", "pool-time-limit" }, + { CFG_NULL, NULL, NULL } +}; + +// store current credentials in pools container +void pool_set_creds(int pooln) +{ + struct pool_infos *p = &pools[pooln]; + + snprintf(p->url, sizeof(p->url), "%s", rpc_url); + snprintf(p->short_url, sizeof(p->short_url), "%s", short_url); + snprintf(p->user, sizeof(p->user), "%s", rpc_user); + snprintf(p->pass, sizeof(p->pass), "%s", rpc_pass); + + if (!(p->status & POOL_ST_DEFINED)) { + p->id = pooln; + p->status |= POOL_ST_DEFINED; + // init pool options as "unset" + // until cmdline is not fully parsed... + p->max_diff = -1.; + p->max_rate = -1.; + p->scantime = -1; + p->time_limit = -1; + + p->allow_mininginfo = allow_mininginfo; + p->allow_gbt = allow_gbt; + p->check_dups = check_dups; + + p->status |= POOL_ST_DEFINED; + } + + if (strlen(rpc_url)) { + if (!strncasecmp(rpc_url, "stratum", 7)) + p->type = POOL_STRATUM; + else /* if (!strncasecmp(rpc_url, "http", 4)) */ + p->type = POOL_GETWORK; // todo: or longpoll + p->status |= POOL_ST_VALID; + } +} + +// fill the unset pools options with cmdline ones +void pool_init_defaults() +{ + struct pool_infos *p; + for (int i=0; imax_diff == -1.) p->max_diff = opt_max_diff; + if (p->max_rate == -1.) p->max_rate = opt_max_rate; + if (p->scantime == -1) p->scantime = opt_scantime; + if (p->time_limit == -1) p->time_limit = opt_time_limit; + } +} + +// attributes only set by a json pools config +void pool_set_attr(int pooln, const char* key, char* arg) +{ + struct pool_infos *p = &pools[pooln]; + + if (!strcasecmp(key, "name")) { + snprintf(p->name, sizeof(p->name), "%s", arg); + return; + } + if (!strcasecmp(key, "scantime")) { + p->scantime = atoi(arg); + return; + } + if (!strcasecmp(key, "max-diff")) { + p->max_diff = atof(arg); + return; + } + if (!strcasecmp(key, "max-rate")) { + p->max_rate = atof(arg); + return; + } + if (!strcasecmp(key, "time-limit")) { + p->time_limit = atoi(arg); + return; + } + if (!strcasecmp(key, "removed")) { + int removed = atoi(arg); + if (removed) { + p->status |= POOL_ST_REMOVED; + } + return; + } +} + +// pool switching code +bool pool_switch(int pooln) +{ + int prevn = cur_pooln; + struct pool_infos *prev = &pools[cur_pooln]; + struct pool_infos* p = NULL; + + // save prev stratum connection infos (struct) + if (prev->type & POOL_STRATUM) { + // may not be the right moment to free, + // to check if required on submit... + stratum_free_job(&stratum); + prev->stratum = stratum; + } + + if (pooln < num_pools) { + cur_pooln = pooln; + p = &pools[cur_pooln]; + } else { + applog(LOG_ERR, "Switch to inexistant pool %d!", pooln); + return false; + } + + // save global attributes + prev->allow_mininginfo = allow_mininginfo; + prev->allow_gbt = allow_gbt; + prev->check_dups = check_dups; + + pthread_mutex_lock(&stratum_work_lock); + + free(rpc_user); rpc_user = strdup(p->user); + free(rpc_pass); rpc_pass = strdup(p->pass); + free(rpc_url); rpc_url = strdup(p->url); + + short_url = p->short_url; // just a pointer, no alloc + + opt_scantime = p->scantime; + opt_max_diff = p->max_diff; + opt_max_rate = p->max_rate; + opt_time_limit = p->time_limit; + + want_stratum = have_stratum = (p->type & POOL_STRATUM) != 0; + + pthread_mutex_unlock(&stratum_work_lock); + + if (prevn != cur_pooln) { + + pool_switch_count++; + g_work_time = 0; + g_work.data[0] = 0; + pool_is_switching = true; + stratum_need_reset = true; + // used to get the pool uptime + firstwork_time = time(NULL); + restart_threads(); + + // restore flags + allow_gbt = p->allow_gbt; + allow_mininginfo = p->allow_mininginfo; + check_dups = p->check_dups; + + if (want_stratum) { + + // temporary... until stratum code cleanup + stratum = p->stratum; + stratum.pooln = cur_pooln; + + // unlock the stratum thread + tq_push(thr_info[stratum_thr_id].q, strdup(rpc_url)); + applog(LOG_BLUE, "Switch to stratum pool %d: %s", cur_pooln, + strlen(p->name) ? p->name : p->short_url); + } else { + applog(LOG_BLUE, "Switch to pool %d: %s", cur_pooln, + strlen(p->name) ? p->name : p->short_url); + } + + // will unlock the longpoll thread on /LP url receive + want_longpoll = (p->type & POOL_LONGPOLL) || !(p->type & POOL_STRATUM); + if (want_longpoll) { + pthread_mutex_lock(&stratum_work_lock); + // will issue a lp_url request to unlock the longpoll thread + have_longpoll = false; + get_work(&thr_info[0], &g_work); + pthread_mutex_unlock(&stratum_work_lock); + } + + } + return true; +} + +// search available pool +int pool_get_first_valid(int startfrom) +{ + int next = 0; + struct pool_infos *p; + for (int i=0; istatus & POOL_ST_VALID)) + continue; + if (p->status & (POOL_ST_DISABLED | POOL_ST_REMOVED)) + continue; + next = pooln; + break; + } + return next; +} + +// switch to next available pool +bool pool_switch_next() +{ + if (num_pools > 1) { + int pooln = pool_get_first_valid(cur_pooln+1); + return pool_switch(pooln); + } else { + // no switch possible + if (!opt_quiet) + applog(LOG_DEBUG, "No other pools to try..."); + return false; + } +} + +// seturl from api remote (deprecated) +bool pool_switch_url(char *params) +{ + int prevn = cur_pooln, nextn; + parse_arg('o', params); + // cur_pooln modified by parse_arg('o'), get new pool num + nextn = cur_pooln; + // and to handle the "hot swap" from current one... + cur_pooln = prevn; + if (nextn == prevn) + return false; + return pool_switch(nextn); +} + +// Parse pools array in json config +bool parse_pool_array(json_t *obj) +{ + size_t idx; + json_t *p, *val; + + if (!json_is_array(obj)) + return false; + + // array of objects [ {}, {} ] + json_array_foreach(obj, idx, p) + { + if (!json_is_object(p)) + continue; + + for (int i = 0; i < ARRAY_SIZE(cfg_array_keys); i++) + { + int opt = -1; + char *s = NULL; + if (cfg_array_keys[i].cat != CFG_POOL) + continue; + + val = json_object_get(p, cfg_array_keys[i].name); + if (!val) + continue; + + for (int k = 0; k < options_count(); k++) + { + const char *alias = cfg_array_keys[i].longname; + if (alias && !strcasecmp(options[k].name, alias)) { + opt = k; + break; + } + if (!alias && !strcasecmp(options[k].name, cfg_array_keys[i].name)) { + opt = k; + break; + } + } + if (opt == -1) + continue; + + if (json_is_string(val)) { + s = strdup(json_string_value(val)); + if (!s) + continue; + + // applog(LOG_DEBUG, "pool key %s '%s'", options[opt].name, s); + parse_arg(options[opt].val, s); + free(s); + } else { + // numeric or bool + char buf[32] = { 0 }; + double d = 0.; + if (json_is_true(val)) d = 1.; + else if (json_is_integer(val)) + d = 1.0 * json_integer_value(val); + else if (json_is_real(val)) + d = json_real_value(val); + snprintf(buf, sizeof(buf)-1, "%f", d); + // applog(LOG_DEBUG, "pool key %s '%f'", options[opt].name, d); + parse_arg(options[opt].val, buf); + } + } + } + return true; +} + +// debug stuff +void pool_dump_infos() +{ + struct pool_infos *p; + for (int i=0; ishort_url, p->user, p->scantime); + } +}