diff --git a/ckpool.conf b/ckpool.conf index fffa2571..ad29587a 100644 --- a/ckpool.conf +++ b/ckpool.conf @@ -13,7 +13,7 @@ ], "btcaddress" : "14BMjogz69qe8hk9thyzbmR5pg34mVKB1e", "btcsig" : "/mined by ck/", -"blockpoll" : 500, +"blockpoll" : 50, "update_interval" : 30, "serverurl" : "ckpool.org:3333", "mindiff" : 1, diff --git a/src/ckpool.c b/src/ckpool.c index c88781ad..6e41347b 100644 --- a/src/ckpool.c +++ b/src/ckpool.c @@ -1208,7 +1208,7 @@ int main(int argc, char **argv) if (!ckp.btcaddress) ckp.btcaddress = ckp.donaddress; if (!ckp.blockpoll) - ckp.blockpoll = 500; + ckp.blockpoll = 50; if (!ckp.update_interval) ckp.update_interval = 30; if (!ckp.mindiff) @@ -1226,6 +1226,18 @@ int main(int argc, char **argv) if (ret && errno != EEXIST) quit(1, "Failed to make log directory %s", ckp.logdir); + /* Create the user logdir */ + sprintf(buf, "%s/users", ckp.logdir); + ret = mkdir(buf, 0750); + if (ret && errno != EEXIST) + quit(1, "Failed to make user log directory %s", buf); + + /* Create the pool logdir */ + sprintf(buf, "%s/pool", ckp.logdir); + ret = mkdir(buf, 0750); + if (ret && errno != EEXIST) + quit(1, "Failed to make pool log directory %s", buf); + /* Create the logfile */ sprintf(buf, "%s%s.log", ckp.logdir, ckp.name); ckp.logfp = fopen(buf, "ae"); diff --git a/src/jansson-2.6/src/strconv.c b/src/jansson-2.6/src/strconv.c index 3e2cb7c4..58cf4ad3 100644 --- a/src/jansson-2.6/src/strconv.c +++ b/src/jansson-2.6/src/strconv.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "jansson_private.h" #include "strbuffer.h" @@ -69,7 +70,7 @@ int jsonp_strtod(strbuffer_t *strbuffer, double *out) value = strtod(strbuffer->value, &end); assert(end == strbuffer->value + strbuffer->length); - if(errno == ERANGE && value != 0) { + if((value == HUGE_VAL || value == -HUGE_VAL) && errno == ERANGE) { /* Overflow */ return -1; } diff --git a/src/stratifier.c b/src/stratifier.c index cef3e8d6..f31d4949 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -195,6 +195,12 @@ struct user_instance { bool btcaddress; int workers; + + double dsps1; /* Diff shares per second, 1 minute rolling average */ + double dsps5; /* ... 5 minute ... */ + double dsps60;/* etc */ + double dsps1440; + tv_t last_share; }; typedef struct user_instance user_instance_t; @@ -260,6 +266,13 @@ static share_t *shares; static cklock_t share_lock; +static int gen_priority; + +/* Priority levels for generator messages */ +#define GEN_LAX 0 +#define GEN_NORMAL 1 +#define GEN_PRIORITY 2 + #define ID_AUTH 0 #define ID_WORKINFO 1 #define ID_AGEWORKINFO 2 @@ -585,17 +598,62 @@ static void add_base(ckpool_t *ckp, workbase_t *wb, bool *new_block) } } +/* Mandatory send_recv to the generator which sets the message priority if this + * message is higher priority. Races galore on gen_priority mean this might + * read the wrong priority but occasional wrong values are harmless. */ +static char *__send_recv_generator(ckpool_t *ckp, const char *msg, int prio) +{ + char *buf = NULL; + bool set; + + if (prio > gen_priority) { + gen_priority = prio; + set = true; + } else + set = false; + buf = send_recv_proc(ckp->generator, msg); + if (set) + gen_priority = 0; + + return buf; +} + +/* Conditionally send_recv a message only if it's equal or higher priority than + * any currently being serviced. */ +static char *send_recv_generator(ckpool_t *ckp, const char *msg, int prio) +{ + char *buf = NULL; + + if (prio >= gen_priority) + buf = __send_recv_generator(ckp, msg, prio); + return buf; +} + +static void send_generator(ckpool_t *ckp, const char *msg, int prio) +{ + bool set; + + if (prio > gen_priority) { + gen_priority = prio; + set = true; + } else + set = false; + send_proc(ckp->generator, msg); + if (set) + gen_priority = 0; +} + /* This function assumes it will only receive a valid json gbt base template * since checking should have been done earlier, and creates the base template * for generating work templates. */ -static void update_base(ckpool_t *ckp) +static void update_base(ckpool_t *ckp, int prio) { bool new_block = false; workbase_t *wb; json_t *val; char *buf; - buf = send_recv_proc(ckp->generator, "getbase"); + buf = send_recv_generator(ckp, "getbase", prio); if (unlikely(!buf)) { LOGWARNING("Failed to get base from generator in update_base"); return; @@ -1020,7 +1078,7 @@ static void block_solve(ckpool_t *ckp) "createinet", ckp->serverurl); ck_runlock(&workbase_lock); - update_base(ckp); + update_base(ckp, GEN_PRIORITY); ck_rlock(&workbase_lock); json_set_string(val, "blockhash", current_workbase->prevhash); @@ -1053,7 +1111,7 @@ retry: copy_tv(&start_tv, &end_tv); LOGDEBUG("%ds elapsed in strat_loop, updating gbt base", ckp->update_interval); - update_base(ckp); + update_base(ckp, GEN_NORMAL); continue; } } @@ -1092,7 +1150,7 @@ retry: ret = 0; goto out; } else if (cmdmatch(buf, "update")) { - update_base(ckp); + update_base(ckp, GEN_PRIORITY); } else if (cmdmatch(buf, "subscribe")) { /* Proxifier has a new subscription */ if (!update_subscribe(ckp)) @@ -1148,7 +1206,7 @@ static void *blockupdate(void *arg) memset(hash, 0, 68); while (42) { dealloc(buf); - buf = send_recv_proc(ckp->generator, request); + buf = send_recv_generator(ckp, request, GEN_LAX); if (buf && strcmp(buf, hash) && !cmdmatch(buf, "failed")) { strcpy(hash, buf); LOGNOTICE("Block hash changed to %s", hash); @@ -1259,7 +1317,8 @@ static bool test_address(ckpool_t *ckp, const char *address) char *buf, *msg; ASPRINTF(&msg, "checkaddr:%s", address); - buf = send_recv_proc(ckp->generator, msg); + /* Must wait for a response here */ + buf = __send_recv_generator(ckp, msg, GEN_LAX); dealloc(msg); if (!buf) return ret; @@ -1505,6 +1564,7 @@ static double sane_tdiff(tv_t *end, tv_t *start) static void add_submit(ckpool_t *ckp, stratum_instance_t *client, int diff, bool valid) { double tdiff, bdiff, dsps, drr, network_diff, bias; + user_instance_t *instance = client->user_instance; int64_t next_blockid, optimal; tv_t now_t; @@ -1518,16 +1578,24 @@ static void add_submit(ckpool_t *ckp, stratum_instance_t *client, int diff, bool network_diff = current_workbase->network_diff; ck_runlock(&workbase_lock); - tdiff = sane_tdiff(&now_t, &client->last_share); if (unlikely(!client->first_share.tv_sec)) { copy_tv(&client->first_share, &now_t); copy_tv(&client->ldc, &now_t); } + + tdiff = sane_tdiff(&now_t, &client->last_share); decay_time(&client->dsps1, diff, tdiff, 60); decay_time(&client->dsps5, diff, tdiff, 300); decay_time(&client->dsps60, diff, tdiff, 3600); decay_time(&client->dsps1440, diff, tdiff, 86400); copy_tv(&client->last_share, &now_t); + + tdiff = sane_tdiff(&now_t, &instance->last_share); + decay_time(&instance->dsps1, diff, tdiff, 60); + decay_time(&instance->dsps5, diff, tdiff, 300); + decay_time(&instance->dsps60, diff, tdiff, 3600); + decay_time(&instance->dsps1440, diff, tdiff, 86400); + copy_tv(&instance->last_share, &now_t); client->idle = false; client->ssdc++; @@ -1562,10 +1630,6 @@ static void add_submit(ckpool_t *ckp, stratum_instance_t *client, int diff, bool return; optimal = round(dsps * 3.33); - /* Don't drop diff to rapidly in case the client simply switched away - * and has just returned */ - if (optimal < client->diff / 2) - optimal = client->diff / 2; /* Clamp to mindiff ~ network_diff */ if (optimal < ckp->mindiff) optimal = ckp->mindiff; @@ -1574,6 +1638,14 @@ static void add_submit(ckpool_t *ckp, stratum_instance_t *client, int diff, bool if (client->diff == optimal) return; + /* If this is the first share in a change, reset the last diff change + * to make sure the client hasn't just fallen back after a leave of + * absence */ + if (optimal < client->diff && client->ssdc == 1) { + copy_tv(&client->ldc, &now_t); + return; + } + client->ssdc = 0; LOGINFO("Client %d biased dsps %.2f dsps %.2f drr %.2f adjust diff from %ld to: %ld ", @@ -1636,7 +1708,7 @@ test_blocksolve(stratum_instance_t *client, workbase_t *wb, const uchar *data, c if (wb->transactions) realloc_strcat(&gbt_block, wb->txn_data); ckp = wb->ckp; - send_proc(ckp->generator, gbt_block); + send_generator(ckp, gbt_block, GEN_PRIORITY); free(gbt_block); flip_32(swap, hash); @@ -1757,7 +1829,7 @@ static void submit_share(stratum_instance_t *client, int64_t jobid, const char * "msg_id", msg_id); msg = json_dumps(json_msg, 0); json_decref(json_msg); - send_proc(ckp->generator, msg); + send_generator(ckp, msg, GEN_LAX); free(msg); } @@ -2417,10 +2489,11 @@ static void *statsupdate(void *arg) while (42) { char suffix1[16], suffix5[16], suffix15[16], suffix60[16], cdfield[64]; - double ghs1, ghs5, ghs15, ghs60, ghs360, ghs1440, tdiff, bias; + double ghs, ghs1, ghs5, ghs15, ghs60, ghs360, ghs1440, tdiff, bias; char suffix360[16], suffix1440[16]; - double sps1, sps5, sps15, sps60; + user_instance_t *instance, *tmpuser; stratum_instance_t *client, *tmp; + double sps1, sps5, sps15, sps60; char fname[512] = {}; tv_t now, diff; ts_t ts_now; @@ -2461,7 +2534,7 @@ static void *statsupdate(void *arg) ghs1440 = stats.dsps1440 * nonces / bias; suffix_string(ghs1440, suffix1440, 16, 0); - snprintf(fname, 511, "%s/pool.status", ckp->logdir); + snprintf(fname, 511, "%s/pool/pool.status", ckp->logdir); fp = fopen(fname, "we"); if (unlikely(!fp)) LOGERR("Failed to fopen %s", fname); @@ -2470,7 +2543,7 @@ static void *statsupdate(void *arg) "runtime", diff.tv_sec, "Users", stats.users, "Workers", stats.workers); - s = json_dumps(val, JSON_NO_UTF8); + s = json_dumps(val, JSON_NO_UTF8 | JSON_PRESERVE_ORDER); json_decref(val); LOGNOTICE("Pool:%s", s); fprintf(fp, "%s\n", s); @@ -2483,7 +2556,7 @@ static void *statsupdate(void *arg) "hashrate1hr", suffix60, "hashrate6hr", suffix360, "hashrate1d", suffix1440); - s = json_dumps(val, JSON_NO_UTF8); + s = json_dumps(val, JSON_NO_UTF8 | JSON_PRESERVE_ORDER); json_decref(val); LOGNOTICE("Pool:%s", s); fprintf(fp, "%s\n", s); @@ -2494,7 +2567,7 @@ static void *statsupdate(void *arg) "SPS5m", sps5, "SPS15m", sps15, "SPS1h", sps60); - s = json_dumps(val, JSON_NO_UTF8); + s = json_dumps(val, JSON_NO_UTF8 | JSON_PRESERVE_ORDER); json_decref(val); LOGNOTICE("Pool:%s", s); fprintf(fp, "%s\n", s); @@ -2503,14 +2576,10 @@ static void *statsupdate(void *arg) ck_rlock(&instance_lock); HASH_ITER(hh, stratum_instances, client, tmp) { - double ghs; - bool idle; - if (!client->authorised) continue; if (now.tv_sec - client->last_share.tv_sec > 60) { - idle = true; /* No shares for over a minute, decay to 0 */ decay_time(&client->dsps1, 0, tdiff, 60); decay_time(&client->dsps5, 0, tdiff, 300); @@ -2518,35 +2587,47 @@ static void *statsupdate(void *arg) decay_time(&client->dsps1440, 0, tdiff, 86400); if (now.tv_sec - client->last_share.tv_sec > 600) client->idle = true; - } else - idle = false; - ghs = client->dsps1 * nonces; + continue; + } + } + + HASH_ITER(hh, user_instances, instance, tmpuser) { + bool idle = false; + + if (now.tv_sec - instance->last_share.tv_sec > 60) { + /* No shares for over a minute, decay to 0 */ + decay_time(&instance->dsps1, 0, tdiff, 60); + decay_time(&instance->dsps5, 0, tdiff, 300); + decay_time(&instance->dsps60, 0, tdiff, 3600); + decay_time(&instance->dsps1440, 0, tdiff, 86400); + idle = true; + } + ghs = instance->dsps1 * nonces; suffix_string(ghs, suffix1, 16, 0); - ghs = client->dsps5 * nonces; + ghs = instance->dsps5 * nonces; suffix_string(ghs, suffix5, 16, 0); - ghs = client->dsps60 * nonces; + ghs = instance->dsps60 * nonces; suffix_string(ghs, suffix60, 16, 0); - ghs = client->dsps1440 * nonces; + ghs = instance->dsps1440 * nonces; suffix_string(ghs, suffix1440, 16, 0); - JSON_CPACK(val, "{ss,ss,ss,ss}", + JSON_CPACK(val, "{ss,ss,ss,ss,si}", "hashrate1m", suffix1, "hashrate5m", suffix5, "hashrate1hr", suffix60, - "hashrate1d", suffix1440); + "hashrate1d", suffix1440, + "workers", instance->workers); - snprintf(fname, 511, "%s/%s", ckp->logdir, client->workername); + snprintf(fname, 511, "%s/users/%s", ckp->logdir, instance->username); fp = fopen(fname, "we"); if (unlikely(!fp)) { LOGERR("Failed to fopen %s", fname); continue; } - s = json_dumps(val, JSON_NO_UTF8); + s = json_dumps(val, JSON_NO_UTF8 | JSON_PRESERVE_ORDER); fprintf(fp, "%s\n", s); - /* Only display the status of connected users to the - * console log. */ if (!idle) - LOGNOTICE("Worker %s:%s", client->workername, s); + LOGNOTICE("User %s:%s", instance->username, s); dealloc(s); json_decref(val); fclose(fp);