From 89422a5a07f28f77116cc4a619bacee42644d87d Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 13 Sep 2014 14:56:19 +1000 Subject: [PATCH 01/10] Avoid allowing any clients with enonce1_64 of zero --- src/stratifier.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index 642322f6..389e1855 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -79,7 +79,7 @@ static pool_stats_t stats; static pthread_mutex_t stats_lock; -static uint64_t enonce1_64; +static uint64_t enonce1_64 = 1; struct workbase { /* Hash table data */ @@ -1027,7 +1027,7 @@ static void drop_client(int64_t id) HASH_DEL(stratum_instances, client); HASH_FIND(hh, disconnected_instances, &client->enonce1_64, sizeof(uint64_t), old_client); /* Only keep around one copy of the old client */ - if (!old_client) + if (!old_client && client->enonce1_64) HASH_ADD(hh, disconnected_instances, enonce1_64, sizeof(uint64_t), client); else // Keep around instance so we don't get a dereference HASH_ADD(hh, dead_instances, enonce1_64, sizeof(uint64_t), client); From 1ff6f771627a5510c9673e42e2548a326ae8f508 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 13 Sep 2014 15:16:52 +1000 Subject: [PATCH 02/10] Avoid duplicating updates on block change from polling and notified update --- src/stratifier.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index 389e1855..8fbfe6e4 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -159,7 +159,7 @@ static struct { static int64_t workbase_id; static int64_t blockchange_id; -static char lasthash[68]; +static char lasthash[68], lastswaphash[68]; struct json_params { json_t *params; @@ -556,10 +556,14 @@ static void add_base(ckpool_t *ckp, workbase_t *wb, bool *new_block) ck_wlock(&workbase_lock); wb->id = workbase_id++; - if (strncmp(wb->prevhash, lasthash, 64)) { + char bin[32], swap[32]; + *new_block = true; memcpy(lasthash, wb->prevhash, 65); + hex2bin(bin, lasthash, 32); + swap_256(swap, bin); + __bin2hex(lastswaphash, swap, 32); blockchange_id = wb->id; } if (*new_block && ckp->logshares) { @@ -1193,7 +1197,7 @@ out: static void *blockupdate(void *arg) { ckpool_t *ckp = (ckpool_t *)arg; - char *buf = NULL, hash[68]; + char *buf = NULL; char request[8]; pthread_detach(pthread_self()); @@ -1204,14 +1208,12 @@ static void *blockupdate(void *arg) else sprintf(request, "getlast"); - memset(hash, 0, 68); while (42) { dealloc(buf); 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); - send_proc(ckp->stratifier, "update"); + if (buf && strcmp(buf, lastswaphash) && !cmdmatch(buf, "failed")) { + LOGNOTICE("Block hash changed to %s", buf); + update_base(ckp, GEN_PRIORITY); } else cksleep_ms(ckp->blockpoll); } From 956be4d8b143acb29fcc33b9ae0ad03abc0391ff Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 13 Sep 2014 22:46:48 +1000 Subject: [PATCH 03/10] Add sanity check for clients sending auth without having completed subscription --- src/stratifier.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/stratifier.c b/src/stratifier.c index 8fbfe6e4..bda81e22 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -1471,6 +1471,10 @@ static json_t *parse_authorise(stratum_instance_t *client, json_t *params_val, j *err_val = json_string("params missing array entries"); goto out; } + if (unlikely(!client->useragent)) { + *err_val = json_string("Failed subscription"); + goto out; + } buf = json_string_value(json_array_get(params_val, 0)); if (!buf) { *err_val = json_string("Invalid workername parameter"); From 92a884f12ac081630bc6efa2cb9089e4240f39c7 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 13 Sep 2014 22:54:40 +1000 Subject: [PATCH 04/10] No valid workinfo should be a share error not a share --- src/stratifier.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index bda81e22..c3e07a68 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -1906,8 +1906,6 @@ static json_t *parse_submit(stratum_instance_t *client, json_t *json_msg, sscanf(job_id, "%lx", &id); sscanf(ntime, "%x", &ntime32); - share = true; - ck_rlock(&workbase_lock); HASH_FIND_I64(workbases, &id, wb); if (unlikely(!wb)) { @@ -1915,8 +1913,10 @@ static json_t *parse_submit(stratum_instance_t *client, json_t *json_msg, json_set_string(json_msg, "reject-reason", SHARE_ERR(err)); strcpy(idstring, job_id); ASPRINTF(&fname, "%s.sharelog", current_workbase->logdir); - goto out_unlock; + ck_runlock(&workbase_lock); + goto out; } + share = true; wdiff = wb->diff; strcpy(idstring, wb->idstring); ASPRINTF(&fname, "%s.sharelog", wb->logdir); From 8fab45147dcc0d2dd4a1c10877b2e6487a6b915f Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 13 Sep 2014 22:56:45 +1000 Subject: [PATCH 05/10] Maintain only one unlock position in parse_submit --- src/stratifier.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index c3e07a68..b650d964 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -1913,8 +1913,7 @@ static json_t *parse_submit(stratum_instance_t *client, json_t *json_msg, json_set_string(json_msg, "reject-reason", SHARE_ERR(err)); strcpy(idstring, job_id); ASPRINTF(&fname, "%s.sharelog", current_workbase->logdir); - ck_runlock(&workbase_lock); - goto out; + goto out_unlock; } share = true; wdiff = wb->diff; @@ -1950,6 +1949,9 @@ static json_t *parse_submit(stratum_instance_t *client, json_t *json_msg, out_unlock: ck_runlock(&workbase_lock); + if (unlikely(!share)) + goto out; + if (submit) submit_share(client, id, nonce2, ntime, nonce, json_integer_value(json_object_get(json_msg, "id"))); From d021692a21a00b2edb9fedd5959cdfb62c21ee0b Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 13 Sep 2014 23:12:32 +1000 Subject: [PATCH 06/10] Abstract out the testing of whether a server is alive to be used for future fallback code --- src/generator.c | 99 +++++++++++++++++++++++++++++-------------------- 1 file changed, 58 insertions(+), 41 deletions(-) diff --git a/src/generator.c b/src/generator.c index e23a173c..aaa3928c 100644 --- a/src/generator.c +++ b/src/generator.c @@ -122,6 +122,60 @@ struct proxy_instance { typedef struct proxy_instance proxy_instance_t; +static bool server_alive(ckpool_t *ckp, server_instance_t *si, bool pinging) +{ + char *userpass = NULL; + bool ret = false; + connsock_t *cs; + gbtbase_t *gbt; + + cs = &si->cs; + if (!extract_sockaddr(si->url, &cs->url, &cs->port)) { + LOGWARNING("Failed to extract address from %s", si->url); + return ret; + } + userpass = strdup(si->auth); + realloc_strcat(&userpass, ":"); + realloc_strcat(&userpass, si->pass); + cs->auth = http_base64(userpass); + dealloc(userpass); + if (!cs->auth) { + LOGWARNING("Failed to create base64 auth from %s", userpass); + return ret; + } + + cs->fd = connect_socket(cs->url, cs->port); + if (cs->fd < 0) { + if (!pinging) + LOGWARNING("Failed to connect socket to %s:%s !", cs->url, cs->port); + return ret; + } + + /* Test we can connect, authorise and get a block template */ + gbt = ckzalloc(sizeof(gbtbase_t)); + si->data = gbt; + if (!gen_gbtbase(cs, gbt)) { + if (!pinging) { + LOGINFO("Failed to get test block template from %s:%s!", + cs->url, cs->port); + } + goto out_close; + } + clear_gbtbase(gbt); + if (!validate_address(cs, ckp->btcaddress)) { + LOGWARNING("Invalid btcaddress: %s !", ckp->btcaddress); + goto out_close; + } + ret = true; +out_close: + if (!ret) + close(cs->fd); + else + keep_sockalive(cs->fd); + return ret; +} + +/* Find the highest priority server alive and return it */ static server_instance_t *live_server(ckpool_t *ckp) { server_instance_t *alive = NULL; @@ -134,49 +188,12 @@ retry: goto out; for (i = 0; i < ckp->btcds; i++) { - server_instance_t *si; - char *userpass = NULL; - gbtbase_t *gbt; - - si = ckp->servers[i]; - cs = &si->cs; - if (!extract_sockaddr(si->url, &cs->url, &cs->port)) { - LOGWARNING("Failed to extract address from %s", si->url); - continue; - } - userpass = strdup(si->auth); - realloc_strcat(&userpass, ":"); - realloc_strcat(&userpass, si->pass); - cs->auth = http_base64(userpass); - dealloc(userpass); - if (!cs->auth) { - LOGWARNING("Failed to create base64 auth from %s", userpass); - continue; - } + server_instance_t *si = ckp->servers[i]; - cs->fd = connect_socket(cs->url, cs->port); - if (cs->fd < 0) { - LOGWARNING("Failed to connect socket to %s:%s !", cs->url, cs->port); - continue; - } - - keep_sockalive(cs->fd); - - /* Test we can connect, authorise and get a block template */ - gbt = ckzalloc(sizeof(gbtbase_t)); - si->data = gbt; - if (!gen_gbtbase(cs, gbt)) { - LOGINFO("Failed to get test block template from %s:%s!", - cs->url, cs->port); - continue; - } - clear_gbtbase(gbt); - if (!validate_address(cs, ckp->btcaddress)) { - LOGWARNING("Invalid btcaddress: %s !", ckp->btcaddress); - continue; + if (server_alive(ckp, si, false)) { + alive = si; + break; } - alive = si; - break; } if (!alive) { LOGWARNING("CRITICAL: No bitcoinds active!"); From ab5d03ece0766a625ad1ed4bcf704266454de219 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 13 Sep 2014 23:26:00 +1000 Subject: [PATCH 07/10] Abstract out testing if a proxy is alive for future fallback code --- src/generator.c | 69 +++++++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/src/generator.c b/src/generator.c index aaa3928c..b119857b 100644 --- a/src/generator.c +++ b/src/generator.c @@ -1270,6 +1270,46 @@ static void passthrough_add_send(proxy_instance_t *proxi, const char *msg) ckmsgq_add(proxi->passsends, pm); } +static bool proxy_alive(ckpool_t *ckp, server_instance_t *si, proxy_instance_t *proxi, + connsock_t *cs, bool pinging) +{ + if (!extract_sockaddr(si->url, &cs->url, &cs->port)) { + LOGWARNING("Failed to extract address from %s", si->url); + return false; + } + if (!connect_proxy(cs)) { + if (!pinging) { + LOGINFO("Failed to connect to %s:%s in proxy_mode!", + cs->url, cs->port); + } + return false; + } + if (ckp->passthrough) { + if (!passthrough_stratum(cs, proxi)) { + LOGWARNING("Failed initial passthrough to %s:%s !", + cs->url, cs->port); + return false; + } + return true; + } + /* Test we can connect, authorise and get stratum information */ + if (!subscribe_stratum(cs, proxi)) { + if (!pinging) { + LOGINFO("Failed initial subscribe to %s:%s !", + cs->url, cs->port); + } + return false; + } + if (!auth_stratum(cs, proxi)) { + if (!pinging) { + LOGWARNING("Failed initial authorise to %s:%s with %s:%s !", + cs->url, cs->port, si->auth, si->pass); + } + return false; + } + return true; +} + /* Cycle through the available proxies and find the first alive one */ static proxy_instance_t *live_proxy(ckpool_t *ckp) { @@ -1289,37 +1329,10 @@ retry: si = ckp->servers[i]; proxi = si->data; cs = proxi->cs; - if (!extract_sockaddr(si->url, &cs->url, &cs->port)) { - LOGWARNING("Failed to extract address from %s", si->url); - continue; - } - if (!connect_proxy(cs)) { - LOGINFO("Failed to connect to %s:%s in proxy_mode!", - cs->url, cs->port); - continue; - } - if (ckp->passthrough) { - if (!passthrough_stratum(cs, proxi)) { - LOGWARNING("Failed initial passthrough to %s:%s !", - cs->url, cs->port); - continue; - } + if (proxy_alive(ckp, si, proxi, cs, false)) { alive = proxi; break; } - /* Test we can connect, authorise and get stratum information */ - if (!subscribe_stratum(cs, proxi)) { - LOGINFO("Failed initial subscribe to %s:%s !", - cs->url, cs->port); - continue; - } - if (!auth_stratum(cs, proxi)) { - LOGWARNING("Failed initial authorise to %s:%s with %s:%s !", - cs->url, cs->port, si->auth, si->pass); - continue; - } - alive = proxi; - break; } if (!alive) { send_proc(ckp->stratifier, "dropall"); From 3cf9fd186ea6c7650a6a478895921754bb6c3724 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 14 Sep 2014 00:08:13 +1000 Subject: [PATCH 08/10] Revert "Maintain only one unlock position in parse_submit" This reverts commit 8fab45147dcc0d2dd4a1c10877b2e6487a6b915f. --- src/stratifier.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index b650d964..c3e07a68 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -1913,7 +1913,8 @@ static json_t *parse_submit(stratum_instance_t *client, json_t *json_msg, json_set_string(json_msg, "reject-reason", SHARE_ERR(err)); strcpy(idstring, job_id); ASPRINTF(&fname, "%s.sharelog", current_workbase->logdir); - goto out_unlock; + ck_runlock(&workbase_lock); + goto out; } share = true; wdiff = wb->diff; @@ -1949,9 +1950,6 @@ static json_t *parse_submit(stratum_instance_t *client, json_t *json_msg, out_unlock: ck_runlock(&workbase_lock); - if (unlikely(!share)) - goto out; - if (submit) submit_share(client, id, nonce2, ntime, nonce, json_integer_value(json_object_get(json_msg, "id"))); From b803c285e1f9f265dea77875c45562045704a096 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 14 Sep 2014 00:08:24 +1000 Subject: [PATCH 09/10] Revert "No valid workinfo should be a share error not a share" This reverts commit 92a884f12ac081630bc6efa2cb9089e4240f39c7. --- src/stratifier.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index c3e07a68..bda81e22 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -1906,6 +1906,8 @@ static json_t *parse_submit(stratum_instance_t *client, json_t *json_msg, sscanf(job_id, "%lx", &id); sscanf(ntime, "%x", &ntime32); + share = true; + ck_rlock(&workbase_lock); HASH_FIND_I64(workbases, &id, wb); if (unlikely(!wb)) { @@ -1913,10 +1915,8 @@ static json_t *parse_submit(stratum_instance_t *client, json_t *json_msg, json_set_string(json_msg, "reject-reason", SHARE_ERR(err)); strcpy(idstring, job_id); ASPRINTF(&fname, "%s.sharelog", current_workbase->logdir); - ck_runlock(&workbase_lock); - goto out; + goto out_unlock; } - share = true; wdiff = wb->diff; strcpy(idstring, wb->idstring); ASPRINTF(&fname, "%s.sharelog", wb->logdir); From 27abc0e84fd1820b4aed0e03e54437828671eded Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 14 Sep 2014 00:09:29 +1000 Subject: [PATCH 10/10] Make invalid workinfo id use the current workbase id --- src/stratifier.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/stratifier.c b/src/stratifier.c index bda81e22..779c3d05 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -1911,6 +1911,7 @@ static json_t *parse_submit(stratum_instance_t *client, json_t *json_msg, ck_rlock(&workbase_lock); HASH_FIND_I64(workbases, &id, wb); if (unlikely(!wb)) { + id = current_workbase->id; err = SE_INVALID_JOBID; json_set_string(json_msg, "reject-reason", SHARE_ERR(err)); strcpy(idstring, job_id);