From 3d6601d20ce523b806455b449d58110cb215d36d Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 26 Sep 2014 09:57:54 +1000 Subject: [PATCH] Maximise the nonce2 size in proxy mode and ensure we don't clash enonce1 instances, rejecting clients when there is no more space available --- src/connector.c | 5 ++- src/stratifier.c | 97 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 83 insertions(+), 19 deletions(-) diff --git a/src/connector.c b/src/connector.c index c7ad4f77..9548f599 100644 --- a/src/connector.c +++ b/src/connector.c @@ -455,9 +455,10 @@ static void send_client(conn_instance_t *ci, int64_t id, char *buf) ck_runlock(&ci->lock); if (unlikely(fd == -1)) { - if (client) + if (client) { LOGINFO("Client id %ld disconnected", id); - else + invalidate_client(ci->pi->ckp, ci, client); + } else LOGINFO("Connector failed to find client id %ld to send to", id); free(buf); return; diff --git a/src/stratifier.c b/src/stratifier.c index 16a9c659..63d4cb07 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 = 1; +static uint64_t enonce1_64; struct workbase { /* Hash table data */ @@ -775,8 +775,10 @@ static bool update_subscribe(ckpool_t *ckp) proxy_base.nonce2len = json_integer_value(json_object_get(val, "nonce2len")); if (proxy_base.nonce2len > 7) proxy_base.enonce1varlen = 4; - else + else if (proxy_base.nonce2len > 5) proxy_base.enonce1varlen = 2; + else + proxy_base.enonce1varlen = 1; proxy_base.enonce2varlen = proxy_base.nonce2len - proxy_base.enonce1varlen; ck_wunlock(&workbase_lock); @@ -1061,6 +1063,8 @@ static void drop_client(int64_t id) stratum_instance_t *client = NULL; bool dec = false; + LOGINFO("Stratifier dropping client %ld", id); + ck_ilock(&instance_lock); client = __instance_by_id(id); if (client) { @@ -1264,32 +1268,84 @@ static void *blockupdate(void *arg) return NULL; } -static void new_enonce1(stratum_instance_t *client) +static inline bool enonce1_free(uint64_t enonce1) +{ + stratum_instance_t *client, *tmp; + bool ret = true; + + if (unlikely(!enonce1)) { + ret = false; + goto out; + } + HASH_ITER(hh, stratum_instances, client, tmp) { + if (client->enonce1_64 == enonce1) { + ret = false; + break; + } + } +out: + return ret; +} + +/* Create a new enonce1 from the 64 bit enonce1_64 value, using only the number + * of bytes we have to work with when we are proxying with a split nonce2. + * When the proxy space is less than 32 bits to work with, we look for an + * unused enonce1 value and reject clients instead if there is no space left */ +static bool new_enonce1(stratum_instance_t *client) { + void *enoncev = &enonce1_64; + uint32_t *enonce1_32 = enoncev; + uint16_t *enonce1_16 = enoncev; + uint8_t *enonce1_8 = enoncev; + bool ret = false; workbase_t *wb; + int i; ck_wlock(&workbase_lock); - client->enonce1_64 = enonce1_64; wb = current_workbase; - if (wb->enonce1varlen == 8) { - enonce1_64++; - } else if (wb->enonce1varlen == 2) { - uint16_t *enonce1_16 = (uint16_t *)&enonce1_64; - - ++(*enonce1_16); - } else { - uint32_t *enonce1_32 = (uint32_t *)&enonce1_64; - - ++(*enonce1_32); + switch(wb->enonce1varlen) { + case 8: + enonce1_64++; + LOGWARNING("Enonce1_64 is %lu", enonce1_64); + ret = true; + break; + case 4: + ++(*enonce1_32); + LOGWARNING("Enonce1_32 is %lu", *enonce1_32); + ret = true; + break; + case 2: + i = 0; + do { + ++(*enonce1_16); + ret = enonce1_free(enonce1_64); + } while (++i < 65536 && !ret); + break; + case 1: + i = 0; + do { + ++(*enonce1_8); + ret = enonce1_free(enonce1_64); + } while (++i < 256 && !ret); + break; } + if (ret) + client->enonce1_64 = enonce1_64; if (wb->enonce1constlen) memcpy(client->enonce1bin, wb->enonce1constbin, wb->enonce1constlen); memcpy(client->enonce1bin + wb->enonce1constlen, &client->enonce1_64, wb->enonce1varlen); __bin2hex(client->enonce1var, &client->enonce1_64, wb->enonce1varlen); __bin2hex(client->enonce1, client->enonce1bin, wb->enonce1constlen + wb->enonce1varlen); ck_wunlock(&workbase_lock); + + if (unlikely(!ret)) + LOGWARNING("Enonce1 space exhausted! Proxy rejecting clients"); + + return ret; } +static void stratum_send_message(stratum_instance_t *client, const char *msg); + /* Extranonce1 must be set here */ static json_t *parse_subscribe(stratum_instance_t *client, int64_t client_id, json_t *params_val) { @@ -1298,11 +1354,15 @@ static json_t *parse_subscribe(stratum_instance_t *client, int64_t client_id, js json_t *ret; int n2len; - if (unlikely(!json_is_array(params_val))) + if (unlikely(!json_is_array(params_val))) { + stratum_send_message(client, "Invalid json: params not an array"); return json_string("params not an array"); + } - if (unlikely(!current_workbase)) + if (unlikely(!current_workbase)) { + stratum_send_message(client, "Pool Initialising"); return json_string("Initialising"); + } arr_size = json_array_size(params_val); if (arr_size > 0) { @@ -1328,7 +1388,10 @@ static json_t *parse_subscribe(stratum_instance_t *client, int64_t client_id, js client->useragent = ckzalloc(1); if (!old_match) { /* Create a new extranonce1 based on a uint64_t pointer */ - new_enonce1(client); + if (!new_enonce1(client)) { + stratum_send_message(client, "Pool full of clients"); + return json_string("proxy full"); + } LOGINFO("Set new subscription %ld to new enonce1 %s", client->id, client->enonce1); } else {