Tanguy Pruvot
10 years ago
6 changed files with 396 additions and 344 deletions
@ -0,0 +1,357 @@
@@ -0,0 +1,357 @@
|
||||
/**
|
||||
* Functions which handle multiple pools data |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
|
||||
#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; i<num_pools; i++) { |
||||
p = &pools[i]; |
||||
if (p->max_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; i<num_pools; i++) { |
||||
int pooln = (startfrom + i) % num_pools; |
||||
p = &pools[pooln]; |
||||
if (!(p->status & 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; i<num_pools; i++) { |
||||
p = &pools[i]; |
||||
applog(LOG_DEBUG, "POOL %01d: %s USER %s -s %d", i, |
||||
p->short_url, p->user, p->scantime); |
||||
} |
||||
} |
Loading…
Reference in new issue