From dc7c57d9c398e7c0e2471cf05ad4b6272171ae8a Mon Sep 17 00:00:00 2001 From: CyberLeo Date: Fri, 26 Oct 2012 09:40:49 -0500 Subject: [PATCH 01/54] Changes to build prototypes to support building on FreeBSD 9.1-RC2 amd64 * Bashism in configure: ./configure: ${ac_cv_search_addstr:2}: Bad substitution * Configure finds libcurl in /usr/local, but /usr/local/include isn't in CFLAGS: cgminer.c:39:10: fatal error: 'curl/curl.h' file not found * Configure misdetects amd64 as 32-bit; fails when trying to link in sse2_64: cgminer-sha256_sse2_amd64.o: In function `scanhash_sse2_64': ./cgminer/sha256_sse2_amd64.c:98: undefined reference to `sha256_sse2_64_new' cgminer-sha256_sse4_amd64.o: In function `scanhash_sse4_64': ./cgminer/sha256_sse4_amd64.c:96: undefined reference to `CalcSha256_x64_sse4' ./cgminer/sha256_sse4_amd64.c:97: undefined reference to `CalcSha256_x64_sse4' --- Makefile.am | 2 +- configure.ac | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index f4ed5e1d..2c3230e0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -26,7 +26,7 @@ cgminer_LDADD = $(DLOPEN_FLAGS) @LIBCURL_LIBS@ @JANSSON_LIBS@ @PTHREAD_LIBS@ \ @OPENCL_LIBS@ @NCURSES_LIBS@ @PDCURSES_LIBS@ @WS2_LIBS@ \ @UDEV_LIBS@ @USB_LIBS@ \ @MATH_LIBS@ lib/libgnu.a ccan/libccan.a -cgminer_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib @OPENCL_FLAGS@ +cgminer_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib @OPENCL_FLAGS@ @LIBCURL_CFLAGS@ # common sources cgminer_SOURCES := cgminer.c diff --git a/configure.ac b/configure.ac index a88f2b7a..8e201c9c 100644 --- a/configure.ac +++ b/configure.ac @@ -70,6 +70,9 @@ WS2_LIBS="" MATH_LIBS="-lm" case $target in + amd64-*) + have_x86_64=true + ;; x86_64-*) have_x86_64=true ;; @@ -257,7 +260,7 @@ if test "x$curses" = "xno"; then else AC_SEARCH_LIBS(addstr, ncurses pdcurses, [ curses=yes - cursesmsg="FOUND: ${ac_cv_search_addstr:2}" + cursesmsg="FOUND: ${ac_cv_search_addstr}" AC_DEFINE([HAVE_CURSES], [1], [Defined to 1 if curses TUI support is wanted]) ], [ if test "x$curses" = "xyes"; then From f4cc59f25f0271ac860bd9baba48fd638a5b98b3 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 1 Nov 2012 13:06:34 +1100 Subject: [PATCH 02/54] Make the rpc request used with getwork a pool variable to allow it to be converted to/from gbt requests. --- cgminer.c | 21 ++++++++++++--------- miner.h | 1 + 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/cgminer.c b/cgminer.c index 0ac54da5..c6812943 100644 --- a/cgminer.c +++ b/cgminer.c @@ -405,6 +405,10 @@ static void sharelog(const char*disposition, const struct work*work) applog(LOG_ERR, "sharelog fwrite error"); } +static char *getwork_req = "{\"method\": \"getwork\", \"params\": [], \"id\":0}\n"; + +// static char *gbt_req = "{\"id\": 0, \"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": [\"coinbasetxn\", \"workid\", \"coinbase/append\"]}]}\n"; + /* Return value is ignored if not called from add_pool_details */ struct pool *add_pool(void) { @@ -427,6 +431,7 @@ struct pool *add_pool(void) /* Make sure the pool doesn't think we've been idle since time 0 */ pool->tv_idle.tv_sec = ~0UL; + pool->rpc_req = getwork_req; pool->rpc_proxy = NULL; return pool; @@ -2158,9 +2163,6 @@ out: return rc; } -static const char *rpc_req = - "{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n"; - /* In balanced mode, the amount of diff1 solutions per pool is monitored as a * rolling average per 10 minutes and if pools start getting more, it biases * away from them to distribute work evenly. The share count is reset to the @@ -2290,13 +2292,13 @@ static bool get_upstream_work(struct work *work, CURL *curl) bool rc = false; char *url; - applog(LOG_DEBUG, "DBG: sending %s get RPC call: %s", pool->rpc_url, rpc_req); + applog(LOG_DEBUG, "DBG: sending %s get RPC call: %s", pool->rpc_url, pool->rpc_req); url = pool->rpc_url; gettimeofday(&(work->tv_getwork), NULL); - val = json_rpc_call(curl, url, pool->rpc_userpass, rpc_req, false, + val = json_rpc_call(curl, url, pool->rpc_userpass, pool->rpc_req, false, false, &work->rolltime, pool, false); pool_stats->getwork_attempts++; @@ -4440,8 +4442,8 @@ retry_stratum: } gettimeofday(&tv_getwork, NULL); - val = json_rpc_call(curl, pool->rpc_url, pool->rpc_userpass, rpc_req, - true, false, &rolltime, pool, false); + val = json_rpc_call(curl, pool->rpc_url, pool->rpc_userpass, + pool->rpc_req, true, false, &rolltime, pool, false); gettimeofday(&tv_getwork_reply, NULL); /* Detect if a http getwork pool has an X-Stratum header at startup, @@ -5361,8 +5363,9 @@ retry_pool: * so always establish a fresh connection instead of relying on * a persistent one. */ curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1); - val = json_rpc_call(curl, pool->lp_url, pool->rpc_userpass, rpc_req, - false, true, &rolltime, pool, false); + val = json_rpc_call(curl, pool->lp_url, pool->rpc_userpass, + pool->rpc_req, false, true, &rolltime, + pool, false); gettimeofday(&reply, NULL); diff --git a/miner.h b/miner.h index 4f79da2a..85111e6c 100644 --- a/miner.h +++ b/miner.h @@ -841,6 +841,7 @@ struct pool { double utility; int last_shares, shares; + char *rpc_req; char *rpc_url; char *rpc_userpass; char *rpc_user, *rpc_pass; From 1c456d4fb33bffb14fe38c7024366dbaa7891647 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 1 Nov 2012 13:53:12 +1100 Subject: [PATCH 03/54] Check for GBT support on first probing the pool and convert to using the GBT request as the rpc request for that pool. --- cgminer.c | 17 ++++++++++++++++- miner.h | 3 +++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index c6812943..2055db6f 100644 --- a/cgminer.c +++ b/cgminer.c @@ -407,7 +407,7 @@ static void sharelog(const char*disposition, const struct work*work) static char *getwork_req = "{\"method\": \"getwork\", \"params\": [], \"id\":0}\n"; -// static char *gbt_req = "{\"id\": 0, \"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": [\"coinbasetxn\", \"workid\", \"coinbase/append\"]}]}\n"; +static char *gbt_req = "{\"id\": 0, \"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": [\"coinbasetxn\", \"workid\", \"coinbase/append\"]}]}\n"; /* Return value is ignored if not called from add_pool_details */ struct pool *add_pool(void) @@ -4441,6 +4441,21 @@ retry_stratum: return false; } + /* Probe for GBT support on first pass */ + if (!pool->probed && !opt_fix_protocol) { + applog(LOG_DEBUG, "Probing for GBT support"); + val = json_rpc_call(curl, pool->rpc_url, pool->rpc_userpass, + gbt_req, true, false, &rolltime, pool, false); + if (val) { + pool->has_gbt = true; + pool->rpc_req = gbt_req; + applog(LOG_DEBUG, "GBT support found, switching to GBT protocol"); + json_decref(val); + } else + applog(LOG_DEBUG, "No GBT support found, using getwork protocol"); + pool->probed = false; + } + gettimeofday(&tv_getwork, NULL); val = json_rpc_call(curl, pool->rpc_url, pool->rpc_userpass, pool->rpc_req, true, false, &rolltime, pool, false); diff --git a/miner.h b/miner.h index 85111e6c..70cbfdf6 100644 --- a/miner.h +++ b/miner.h @@ -883,6 +883,9 @@ struct pool { struct stratum_work swork; pthread_t stratum_thread; pthread_mutex_t stratum_lock; + + /* GBT variables */ + bool has_gbt; }; #define GETWORK_MODE_TESTPOOL 'T' From 8afc1f6512135dc0469afc6d4e5571fcea337c79 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 1 Nov 2012 14:05:25 +1100 Subject: [PATCH 04/54] Convert work decode function to prepare for decoding block templates. --- cgminer.c | 35 ++++++++++++++++++++++------------- miner.h | 2 ++ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/cgminer.c b/cgminer.c index 2055db6f..946b654f 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1358,37 +1358,46 @@ static void calc_midstate(struct work *work) #endif } -static bool work_decode(const json_t *val, struct work *work) +static bool work_decode(struct pool *pool, struct work *work, json_t *val) { - if (unlikely(!jobj_binary(val, "data", work->data, sizeof(work->data), true))) { + bool ret = false; + json_t *res_val; + + if (pool->has_gbt) { + work->gbt = true; + goto out; + } + + res_val = json_object_get(val, "result"); + if (unlikely(!jobj_binary(res_val, "data", work->data, sizeof(work->data), true))) { applog(LOG_ERR, "JSON inval data"); - goto err_out; + goto out; } - if (!jobj_binary(val, "midstate", work->midstate, sizeof(work->midstate), false)) { + if (!jobj_binary(res_val, "midstate", work->midstate, sizeof(work->midstate), false)) { // Calculate it ourselves applog(LOG_DEBUG, "Calculating midstate locally"); calc_midstate(work); } - if (!jobj_binary(val, "hash1", work->hash1, sizeof(work->hash1), false)) { + if (!jobj_binary(res_val, "hash1", work->hash1, sizeof(work->hash1), false)) { // Always the same anyway memcpy(work->hash1, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0", 64); } - if (unlikely(!jobj_binary(val, "target", work->target, sizeof(work->target), true))) { + if (unlikely(!jobj_binary(res_val, "target", work->target, sizeof(work->target), true))) { applog(LOG_ERR, "JSON inval target"); - goto err_out; + goto out; } memset(work->hash, 0, sizeof(work->hash)); gettimeofday(&work->tv_staged, NULL); - return true; + ret = true; -err_out: - return false; +out: + return ret; } int dev_from_id(int thr_id) @@ -2303,7 +2312,7 @@ static bool get_upstream_work(struct work *work, CURL *curl) pool_stats->getwork_attempts++; if (likely(val)) { - rc = work_decode(json_object_get(val, "result"), work); + rc = work_decode(pool, work, val); if (unlikely(!rc)) applog(LOG_DEBUG, "Failed to decode work in get_upstream_work"); } else @@ -4477,7 +4486,7 @@ retry_stratum: struct work *work = make_work(); bool rc; - rc = work_decode(json_object_get(val, "result"), work); + rc = work_decode(pool, work, val); if (rc) { applog(LOG_DEBUG, "Successfully retrieved and deciphered work from pool %u %s", pool->pool_no, pool->rpc_url); @@ -5254,7 +5263,7 @@ static void convert_to_work(json_t *val, int rolltime, struct pool *pool, struct work = make_work(); - rc = work_decode(json_object_get(val, "result"), work); + rc = work_decode(pool, work, val); if (unlikely(!rc)) { applog(LOG_ERR, "Could not convert longpoll data to work"); free_work(work); diff --git a/miner.h b/miner.h index 70cbfdf6..e608c13c 100644 --- a/miner.h +++ b/miner.h @@ -930,6 +930,8 @@ struct work { char ntime[16]; int sdiff; + bool gbt; + unsigned int work_block; int id; UT_hash_handle hh; From d10699d4c33de94f985b4af4502e1649b837b213 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 1 Nov 2012 14:24:55 +1100 Subject: [PATCH 05/54] Add a gbt mutex within the pool struct for protecting the gbt values. --- cgminer.c | 7 +++---- miner.h | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cgminer.c b/cgminer.c index 946b654f..10c6a5b3 100644 --- a/cgminer.c +++ b/cgminer.c @@ -420,12 +420,11 @@ struct pool *add_pool(void) pool->pool_no = pool->prio = total_pools; pools = realloc(pools, sizeof(struct pool *) * (total_pools + 2)); pools[total_pools++] = pool; - if (unlikely(pthread_mutex_init(&pool->pool_lock, NULL))) - quit(1, "Failed to pthread_mutex_init in add_pool"); + mutex_init(&pool->pool_lock); if (unlikely(pthread_cond_init(&pool->cr_cond, NULL))) quit(1, "Failed to pthread_cond_init in add_pool"); - if (unlikely(pthread_mutex_init(&pool->stratum_lock, NULL))) - quit(1, "Failed to pthread_mutex_init in add_pool"); + mutex_init(&pool->stratum_lock); + mutex_init(&pool->gbt_lock); INIT_LIST_HEAD(&pool->curlring); /* Make sure the pool doesn't think we've been idle since time 0 */ diff --git a/miner.h b/miner.h index e608c13c..278b2be8 100644 --- a/miner.h +++ b/miner.h @@ -886,6 +886,7 @@ struct pool { /* GBT variables */ bool has_gbt; + pthread_mutex_t gbt_lock; }; #define GETWORK_MODE_TESTPOOL 'T' From 26e01150307435e1a2647903fbdcadbfa2e41eae Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 1 Nov 2012 15:36:22 +1100 Subject: [PATCH 06/54] Check for the coinbase/append mutable in GBT support to decide whether to use it or not. --- cgminer.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/cgminer.c b/cgminer.c index 10c6a5b3..ee944246 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1359,15 +1359,14 @@ static void calc_midstate(struct work *work) static bool work_decode(struct pool *pool, struct work *work, json_t *val) { + json_t *res_val = json_object_get(val, "result"); bool ret = false; - json_t *res_val; if (pool->has_gbt) { work->gbt = true; goto out; } - res_val = json_object_get(val, "result"); if (unlikely(!jobj_binary(res_val, "data", work->data, sizeof(work->data), true))) { applog(LOG_ERR, "JSON inval data"); goto out; @@ -4455,13 +4454,36 @@ retry_stratum: val = json_rpc_call(curl, pool->rpc_url, pool->rpc_userpass, gbt_req, true, false, &rolltime, pool, false); if (val) { - pool->has_gbt = true; - pool->rpc_req = gbt_req; - applog(LOG_DEBUG, "GBT support found, switching to GBT protocol"); + json_t *res_val, *mutables; + int i, mutsize = 0; + + res_val = json_object_get(val, "result"); + if (res_val) { + mutables = json_object_get(res_val, "mutable"); + mutsize = json_array_size(mutables); + } + + for (i = 0; i < mutsize; i++) { + json_t *arrval = json_array_get(mutables, i); + + if (json_is_string(arrval)) { + const char *mutable = json_string_value(arrval); + + /* Only use GBT if it supports coinbase append */ + if (!strncasecmp(mutable, "coinbase/append", 15)) { + pool->has_gbt = true; + pool->rpc_req = gbt_req; + break; + } + } + } json_decref(val); - } else - applog(LOG_DEBUG, "No GBT support found, using getwork protocol"); + } pool->probed = false; + if (pool->has_gbt) + applog(LOG_DEBUG, "GBT coinbase append support found, switching to GBT protocol"); + else + applog(LOG_DEBUG, "No GBT coinbase append support found, using getwork protocol"); } gettimeofday(&tv_getwork, NULL); From 56b16953a94d7e672c84cf1144747948557350c5 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 1 Nov 2012 15:40:07 +1100 Subject: [PATCH 07/54] Decode work in separate functions for getwork vs gbt. --- cgminer.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/cgminer.c b/cgminer.c index ee944246..b1dc39f0 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1357,19 +1357,11 @@ static void calc_midstate(struct work *work) #endif } -static bool work_decode(struct pool *pool, struct work *work, json_t *val) +static bool getwork_decode(json_t *res_val, struct work *work) { - json_t *res_val = json_object_get(val, "result"); - bool ret = false; - - if (pool->has_gbt) { - work->gbt = true; - goto out; - } - if (unlikely(!jobj_binary(res_val, "data", work->data, sizeof(work->data), true))) { applog(LOG_ERR, "JSON inval data"); - goto out; + return false; } if (!jobj_binary(res_val, "midstate", work->midstate, sizeof(work->midstate), false)) { @@ -1385,9 +1377,24 @@ static bool work_decode(struct pool *pool, struct work *work, json_t *val) if (unlikely(!jobj_binary(res_val, "target", work->target, sizeof(work->target), true))) { applog(LOG_ERR, "JSON inval target"); + return false; + } + return true; +} + +static bool work_decode(struct pool *pool, struct work *work, json_t *val) +{ + json_t *res_val = json_object_get(val, "result"); + bool ret = false; + + if (pool->has_gbt) { + work->gbt = true; goto out; } + if (unlikely(!getwork_decode(res_val, work))) + goto out; + memset(work->hash, 0, sizeof(work->hash)); gettimeofday(&work->tv_staged, NULL); From 432b2636d537f3e6f789ecc5bc6899266c625d78 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 1 Nov 2012 15:41:32 +1100 Subject: [PATCH 08/54] Check for invalid json result in work_decode. --- cgminer.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cgminer.c b/cgminer.c index b1dc39f0..8464c078 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1387,6 +1387,11 @@ static bool work_decode(struct pool *pool, struct work *work, json_t *val) json_t *res_val = json_object_get(val, "result"); bool ret = false; + if (!res_val || json_is_null(res_val)) { + applog(LOG_ERR, "JSON Failed to decode result"); + goto out; + } + if (pool->has_gbt) { work->gbt = true; goto out; From 813e814f6cf89f1ffca48a65d258fc1961082e85 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 1 Nov 2012 16:56:54 +1100 Subject: [PATCH 09/54] Extract and store the various variables GBT uses when decoding gbt work. --- cgminer.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- miner.h | 10 +++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/cgminer.c b/cgminer.c index 8464c078..5f1fc08c 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1357,6 +1357,64 @@ static void calc_midstate(struct work *work) #endif } +static bool gbt_decode(struct pool *pool, json_t *res_val) +{ + const char *previousblockhash; + const char *target; + const char *coinbasetxn; + const char *longpollid; + int expires; + int version; + int curtime; + bool submitold; + const char *bits; + + previousblockhash = json_string_value(json_object_get(res_val, "previousblockhash")); + target = json_string_value(json_object_get(res_val, "target")); + coinbasetxn = json_string_value(json_object_get(json_object_get(res_val, "coinbasetxn"), "data")); + longpollid = json_string_value(json_object_get(res_val, "longpollid")); + expires = json_integer_value(json_object_get(res_val, "expires")); + version = json_integer_value(json_object_get(res_val, "version")); + curtime = json_integer_value(json_object_get(res_val, "curtime")); + submitold = json_is_true(json_object_get(res_val, "submitold")); + bits = json_string_value(json_object_get(res_val, "bits")); + + if (!previousblockhash || !target || !coinbasetxn || !longpollid || + !expires || !version || !curtime || !bits) { + applog(LOG_ERR, "JSON failed to decode GBT"); + return false; + } + + applog(LOG_DEBUG, "previousblockhash: %s", previousblockhash); + applog(LOG_DEBUG, "target: %s", target); + applog(LOG_DEBUG, "coinbasetxn: %s", coinbasetxn); + applog(LOG_DEBUG, "longpollid: %s", longpollid); + applog(LOG_DEBUG, "expires: %d", expires); + applog(LOG_DEBUG, "version: %d", version); + applog(LOG_DEBUG, "curtime: %d", curtime); + applog(LOG_DEBUG, "submitold: %s", submitold ? "true" : "false"); + applog(LOG_DEBUG, "bits: %s", bits); + + mutex_lock(&pool->gbt_lock); + free(pool->previousblockhash); + free(pool->gbt_target); + free(pool->coinbasetxn); + free(pool->longpollid); + free(pool->gbt_bits); + pool->previousblockhash = strdup(previousblockhash); + pool->gbt_target = strdup(target); + pool->coinbasetxn = strdup(coinbasetxn); + pool->longpollid = strdup(longpollid); + pool->gbt_expires = expires; + pool->gbt_version = htobe32(version); + pool->curtime = htobe32(curtime); + pool->gbt_submitold = submitold; + pool->gbt_bits = strdup(bits); + mutex_unlock(&pool->gbt_lock); + + return true; +} + static bool getwork_decode(json_t *res_val, struct work *work) { if (unlikely(!jobj_binary(res_val, "data", work->data, sizeof(work->data), true))) { @@ -1393,11 +1451,12 @@ static bool work_decode(struct pool *pool, struct work *work, json_t *val) } if (pool->has_gbt) { + if (unlikely(!gbt_decode(pool, res_val))) + goto out; work->gbt = true; + ret = true; goto out; - } - - if (unlikely(!getwork_decode(res_val, work))) + } else if (unlikely(!getwork_decode(res_val, work))) goto out; memset(work->hash, 0, sizeof(work->hash)); diff --git a/miner.h b/miner.h index 278b2be8..0b20984a 100644 --- a/miner.h +++ b/miner.h @@ -887,6 +887,16 @@ struct pool { /* GBT variables */ bool has_gbt; pthread_mutex_t gbt_lock; + char *previousblockhash; + char *gbt_target; + char *coinbasetxn; + char *longpollid; + int gbt_expires; + uint32_t gbt_version; + uint32_t curtime; + bool gbt_submitold; + char *gbt_bits; + }; #define GETWORK_MODE_TESTPOOL 'T' From 4a72a1574f88fce9d20b1a2cbbb3c8b332092791 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 1 Nov 2012 22:34:08 +1100 Subject: [PATCH 10/54] Create a function that generates a GBT coinbase from the existing pool variables. --- cgminer.c | 24 +++++++++++++++++++++++- miner.h | 1 + 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 5f1fc08c..384a9a9c 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1357,6 +1357,27 @@ static void calc_midstate(struct work *work) #endif } +/* Generate a GBT coinbase from the existing GBT variables stored. Must be + * entered under gbt_lock */ +static void __build_gbt_coinbase(struct pool *pool) +{ + unsigned char *coinbase; + uint8_t *extra_len; + int cbt_len; + + cbt_len = strlen(pool->coinbasetxn) / 2; + /* We add 4 bytes of extra data corresponding to nonce2 of stratum */ + coinbase = calloc(cbt_len + 4, 1); + hex2bin(coinbase, pool->coinbasetxn, 42); + extra_len = (uint8_t *)(coinbase + 41); + *extra_len += 4; + hex2bin(coinbase + 42, pool->coinbasetxn + 84, cbt_len - 42); + pool->nonce2++; + memcpy(coinbase + cbt_len, &pool->nonce2, 4); + free(pool->gbt_coinbase); + pool->gbt_coinbase = coinbase; +} + static bool gbt_decode(struct pool *pool, json_t *res_val) { const char *previousblockhash; @@ -1394,7 +1415,7 @@ static bool gbt_decode(struct pool *pool, json_t *res_val) applog(LOG_DEBUG, "curtime: %d", curtime); applog(LOG_DEBUG, "submitold: %s", submitold ? "true" : "false"); applog(LOG_DEBUG, "bits: %s", bits); - + mutex_lock(&pool->gbt_lock); free(pool->previousblockhash); free(pool->gbt_target); @@ -1410,6 +1431,7 @@ static bool gbt_decode(struct pool *pool, json_t *res_val) pool->curtime = htobe32(curtime); pool->gbt_submitold = submitold; pool->gbt_bits = strdup(bits); + __build_gbt_coinbase(pool); mutex_unlock(&pool->gbt_lock); return true; diff --git a/miner.h b/miner.h index 0b20984a..e21228ad 100644 --- a/miner.h +++ b/miner.h @@ -896,6 +896,7 @@ struct pool { uint32_t curtime; bool gbt_submitold; char *gbt_bits; + unsigned char *gbt_coinbase; }; From 8d0f7482464ec7e1a515b2a0232f6c0a74a9aca0 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 3 Nov 2012 13:27:41 +1100 Subject: [PATCH 11/54] Create a store of the transactions with GBT in the minimum size form required to generate work items with a varied coinbase. --- cgminer.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ miner.h | 4 +++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 384a9a9c..6252d6de 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1378,6 +1378,61 @@ static void __build_gbt_coinbase(struct pool *pool) pool->gbt_coinbase = coinbase; } +static void gen_hash(unsigned char *data, unsigned char *hash, int len); + +/* Process transactions with GBT by storing the binary value of the first + * transaction, and the hashes of the remaining transactions since these + * remain constant with an altered coinbase when generating work. Must be + * entered under gbt_lock */ +static bool __build_gbt_txns(struct pool *pool, json_t *res_val) +{ + json_t *txn_array; + const char *txn0; + bool ret = false; + int i; + + free(pool->txn0); + pool->txn0 = NULL; + free(pool->txn_hashes); + pool->txn_hashes = NULL; + pool->gbt_txns = 0; + + txn_array = json_object_get(res_val, "transactions"); + if (!json_is_array(txn_array)) + goto out; + + ret = true; + pool->gbt_txns = json_array_size(txn_array); + if (!pool->gbt_txns) + goto out; + + txn0 = json_string_value(json_object_get(json_array_get(txn_array, 0), "data")); + if (!hex2bin(pool->txn0, txn0, strlen(txn0) / 2)) + quit(1, "Failed to hex2bin txn0"); + pool->txn_hashes = calloc(32 * pool->gbt_txns, 1); + if (unlikely(!pool->txn_hashes)) + quit(1, "Failed to calloc txn_hashes in __build_gbt_txns"); + + for (i = 1; i < pool->gbt_txns; i++) { + json_t *txn_val = json_object_get(json_array_get(txn_array, i), "data"); + const char *txn = json_string_value(txn_val); + int txn_len = strlen(txn), binlen; + unsigned char *txn_bin; + + binlen = txn_len % 4 ? txn_len + 4 - (txn_len % 4) : txn_len; + txn_bin = calloc(binlen, 1); + if (unlikely(!txn_bin)) + quit(1, "Failed to calloc txn_bin in __build_gbt_txns"); + if (unlikely(!hex2bin(txn_bin, txn, txn_len / 2))) + quit(1, "Failed to hex2bin txn_bin"); + + gen_hash(txn_bin, pool->txn_hashes + (32 * (i - 1)), txn_len); + free(txn_bin); + } +out: + return ret; +} + static bool gbt_decode(struct pool *pool, json_t *res_val) { const char *previousblockhash; @@ -1432,6 +1487,7 @@ static bool gbt_decode(struct pool *pool, json_t *res_val) pool->gbt_submitold = submitold; pool->gbt_bits = strdup(bits); __build_gbt_coinbase(pool); + __build_gbt_txns(pool, res_val); mutex_unlock(&pool->gbt_lock); return true; diff --git a/miner.h b/miner.h index e21228ad..a0bfc718 100644 --- a/miner.h +++ b/miner.h @@ -897,7 +897,9 @@ struct pool { bool gbt_submitold; char *gbt_bits; unsigned char *gbt_coinbase; - + unsigned char *txn0; + unsigned char *txn_hashes; + int gbt_txns; }; #define GETWORK_MODE_TESTPOOL 'T' From cbc246eace96f6f85e8c0364344e718fa0ef6bae Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 3 Nov 2012 19:45:37 +1100 Subject: [PATCH 12/54] Generate the merkle root for gbt work generation. --- cgminer.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- miner.h | 2 ++ 2 files changed, 78 insertions(+), 3 deletions(-) diff --git a/cgminer.c b/cgminer.c index 6252d6de..0f5e977b 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1366,8 +1366,9 @@ static void __build_gbt_coinbase(struct pool *pool) int cbt_len; cbt_len = strlen(pool->coinbasetxn) / 2; + pool->coinbase_len = cbt_len + 4; /* We add 4 bytes of extra data corresponding to nonce2 of stratum */ - coinbase = calloc(cbt_len + 4, 1); + coinbase = calloc(pool->coinbase_len, 1); hex2bin(coinbase, pool->coinbasetxn, 42); extra_len = (uint8_t *)(coinbase + 41); *extra_len += 4; @@ -1407,7 +1408,11 @@ static bool __build_gbt_txns(struct pool *pool, json_t *res_val) goto out; txn0 = json_string_value(json_object_get(json_array_get(txn_array, 0), "data")); - if (!hex2bin(pool->txn0, txn0, strlen(txn0) / 2)) + pool->txn0_len = strlen(txn0) / 2; + pool->txn0 = calloc(pool->txn0_len , 1);; + if (unlikely(!pool->txn0)) + quit(1, "Failed to calloc pool->txn0"); + if (!hex2bin(pool->txn0, txn0, pool->txn0_len)) quit(1, "Failed to hex2bin txn0"); pool->txn_hashes = calloc(32 * pool->gbt_txns, 1); if (unlikely(!pool->txn_hashes)) @@ -1433,6 +1438,63 @@ out: return ret; } +static unsigned char *__gbt_merkleroot(struct pool *pool) +{ + unsigned char *merkles, *txn0, *merkle_hash; + int i, txns; + + if (!pool->gbt_txns) { + pool->txn0 = (unsigned char *)strdup((const char *)pool->gbt_coinbase); + pool->txn0_len = pool->coinbase_len; + } + + txn0 = calloc(pool->coinbase_len + pool->txn0_len, 1); + if (unlikely(!txn0)) + quit(1, "Failed to calloc txn0hash"); + + memcpy(txn0, pool->gbt_coinbase, pool->coinbase_len); + memcpy(txn0 + pool->coinbase_len, pool->txn0, pool->txn0_len); + + merkles = calloc(32 + (32 * pool->gbt_txns), 1); + if (unlikely(!merkles)) + quit(1, "Failed to calloc merkles in __gbt_merkleroot"); + + gen_hash(txn0, merkles, pool->coinbase_len + pool->txn0_len); + free(txn0); + + if (pool->gbt_txns > 1) + memcpy(merkles + 32, pool->txn_hashes, (pool->gbt_txns - 1) * 32); + + merkle_hash = calloc((pool->gbt_txns + 1) * 32, 1); + if (unlikely(!merkle_hash)) + quit(1, "Failed to calloc merkle_hash in __gbt_merkleroot"); + + txns = pool->gbt_txns + 1; + for (i = 0; i < txns; i++){ + unsigned char tohash[64]; + + memcpy(tohash, &merkles[i * 32], 32); + if (i + 1 < txns) + memcpy(tohash + 32, &merkles[(i + 1) * 32], 32); + else + memcpy(tohash + 32, &merkles[i * 32], 32); + gen_hash(tohash, merkle_hash + (i * 32), 64); + } + return merkle_hash; +} + +static void gen_gbt_work(struct pool *pool, struct work *work) +{ + unsigned char *merkleroot; + + mutex_lock(&pool->gbt_lock); + __build_gbt_coinbase(pool); + merkleroot = __gbt_merkleroot(pool); + mutex_unlock(&pool->gbt_lock); + + free(merkleroot); +} + static bool gbt_decode(struct pool *pool, json_t *res_val) { const char *previousblockhash; @@ -1486,7 +1548,6 @@ static bool gbt_decode(struct pool *pool, json_t *res_val) pool->curtime = htobe32(curtime); pool->gbt_submitold = submitold; pool->gbt_bits = strdup(bits); - __build_gbt_coinbase(pool); __build_gbt_txns(pool, res_val); mutex_unlock(&pool->gbt_lock); @@ -2919,6 +2980,18 @@ retry: goto out; } + if (pool->has_gbt) { + ret_work = make_work(); + gen_gbt_work(pool, ret_work); + if (unlikely(!stage_work(ret_work))) { + applog(LOG_ERR, "Failed to stage gbt work in get_work_thread"); + kill_work(); + free(ret_work); + } + dec_queued(pool); + goto out; + } + if (clone_available()) { dec_queued(pool); goto out; diff --git a/miner.h b/miner.h index a0bfc718..6645f17a 100644 --- a/miner.h +++ b/miner.h @@ -900,6 +900,8 @@ struct pool { unsigned char *txn0; unsigned char *txn_hashes; int gbt_txns; + int txn0_len; + int coinbase_len; }; #define GETWORK_MODE_TESTPOOL 'T' From 2bfb293fe3ebb83ab385dcdcef51655d2a3cc200 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 4 Nov 2012 00:52:50 +1100 Subject: [PATCH 13/54] Generate header from correct hashing generation of the merkle root for GBT. --- cgminer.c | 67 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/cgminer.c b/cgminer.c index 0f5e977b..6834af1a 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1362,13 +1362,16 @@ static void calc_midstate(struct work *work) static void __build_gbt_coinbase(struct pool *pool) { unsigned char *coinbase; + int cbt_len, cal_len; uint8_t *extra_len; - int cbt_len; cbt_len = strlen(pool->coinbasetxn) / 2; pool->coinbase_len = cbt_len + 4; /* We add 4 bytes of extra data corresponding to nonce2 of stratum */ - coinbase = calloc(pool->coinbase_len, 1); + cal_len = pool->coinbase_len + 1; + if (cal_len % 4) + cal_len += 4 - (cal_len % 4); + coinbase = calloc(cal_len, 1); hex2bin(coinbase, pool->coinbasetxn, 42); extra_len = (uint8_t *)(coinbase + 41); *extra_len += 4; @@ -1390,7 +1393,7 @@ static bool __build_gbt_txns(struct pool *pool, json_t *res_val) json_t *txn_array; const char *txn0; bool ret = false; - int i; + int i, cal_len; free(pool->txn0); pool->txn0 = NULL; @@ -1409,7 +1412,10 @@ static bool __build_gbt_txns(struct pool *pool, json_t *res_val) txn0 = json_string_value(json_object_get(json_array_get(txn_array, 0), "data")); pool->txn0_len = strlen(txn0) / 2; - pool->txn0 = calloc(pool->txn0_len , 1);; + cal_len = pool->txn0_len; + if (cal_len % 4) + cal_len += 4 - (cal_len % 4); + pool->txn0 = calloc(cal_len , 1); if (unlikely(!pool->txn0)) quit(1, "Failed to calloc pool->txn0"); if (!hex2bin(pool->txn0, txn0, pool->txn0_len)) @@ -1421,11 +1427,13 @@ static bool __build_gbt_txns(struct pool *pool, json_t *res_val) for (i = 1; i < pool->gbt_txns; i++) { json_t *txn_val = json_object_get(json_array_get(txn_array, i), "data"); const char *txn = json_string_value(txn_val); - int txn_len = strlen(txn), binlen; + int txn_len = strlen(txn); unsigned char *txn_bin; - binlen = txn_len % 4 ? txn_len + 4 - (txn_len % 4) : txn_len; - txn_bin = calloc(binlen, 1); + cal_len = txn_len; + if (cal_len % 4) + cal_len += 4 - (cal_len % 4); + txn_bin = calloc(cal_len, 1); if (unlikely(!txn_bin)) quit(1, "Failed to calloc txn_bin in __build_gbt_txns"); if (unlikely(!hex2bin(txn_bin, txn, txn_len / 2))) @@ -1441,21 +1449,25 @@ out: static unsigned char *__gbt_merkleroot(struct pool *pool) { unsigned char *merkles, *txn0, *merkle_hash; - int i, txns; + int i, txns, cal_len; if (!pool->gbt_txns) { pool->txn0 = (unsigned char *)strdup((const char *)pool->gbt_coinbase); pool->txn0_len = pool->coinbase_len; } - txn0 = calloc(pool->coinbase_len + pool->txn0_len, 1); + cal_len = pool->coinbase_len + pool->txn0_len; + if (cal_len % 4) + cal_len += 4 - (cal_len % 4); + txn0 = calloc(cal_len, 1); if (unlikely(!txn0)) quit(1, "Failed to calloc txn0hash"); memcpy(txn0, pool->gbt_coinbase, pool->coinbase_len); memcpy(txn0 + pool->coinbase_len, pool->txn0, pool->txn0_len); - merkles = calloc(32 + (32 * pool->gbt_txns), 1); + cal_len = 32 + (32 * pool->gbt_txns); + merkles = calloc(cal_len, 1); if (unlikely(!merkles)) quit(1, "Failed to calloc merkles in __gbt_merkleroot"); @@ -1465,20 +1477,24 @@ static unsigned char *__gbt_merkleroot(struct pool *pool) if (pool->gbt_txns > 1) memcpy(merkles + 32, pool->txn_hashes, (pool->gbt_txns - 1) * 32); - merkle_hash = calloc((pool->gbt_txns + 1) * 32, 1); + cal_len = (pool->gbt_txns + 1) * 32; + merkle_hash = calloc(cal_len, 1); if (unlikely(!merkle_hash)) quit(1, "Failed to calloc merkle_hash in __gbt_merkleroot"); txns = pool->gbt_txns + 1; - for (i = 0; i < txns; i++){ - unsigned char tohash[64]; + while (txns > 1) { + if (txns % 2) { + memcpy(&merkles[txns * 32], &merkles[(txns - 1) * 32], 32); + txns++; + } + for (i = 0; i < txns; i += 2){ + unsigned char hashout[32]; - memcpy(tohash, &merkles[i * 32], 32); - if (i + 1 < txns) - memcpy(tohash + 32, &merkles[(i + 1) * 32], 32); - else - memcpy(tohash + 32, &merkles[i * 32], 32); - gen_hash(tohash, merkle_hash + (i * 32), 64); + gen_hash(merkle_hash + (i * 32), hashout, 64); + memcpy(merkle_hash + (i / 2 * 32), hashout, 32); + } + txns /= 2; } return merkle_hash; } @@ -1490,8 +1506,21 @@ static void gen_gbt_work(struct pool *pool, struct work *work) mutex_lock(&pool->gbt_lock); __build_gbt_coinbase(pool); merkleroot = __gbt_merkleroot(pool); + memcpy(work->data, &pool->gbt_version, 4); + hex2bin(work->data + 4, pool->previousblockhash, 32); + memcpy(work->data + 4 + 32, merkleroot, 32); + memcpy(work->data + 4 + 32 + 32, &pool->curtime, 4); + hex2bin(work->data + 4 + 32 + 32 + 4, pool->gbt_bits, 4); + memset(work->data + 4 + 32 + 32 + 4 + 4, 0, 4); /* nonce */ mutex_unlock(&pool->gbt_lock); + if (opt_debug) { + char *header = bin2hex(work->data, 4 + 32 + 32 + 4 + 4 + 4); + + applog(LOG_DEBUG, "Generated GBT header %s", header); + free(header); + } + free(merkleroot); } From 875ca0fcc6d2882dfbabebda507e556d8f61f8c9 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 4 Nov 2012 01:07:01 +1100 Subject: [PATCH 14/54] Create extra work fields when generating GBT work. --- cgminer.c | 26 ++++++++++++++++++++++---- miner.h | 1 + 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/cgminer.c b/cgminer.c index 6834af1a..04b21da1 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1498,7 +1498,9 @@ static unsigned char *__gbt_merkleroot(struct pool *pool) } return merkle_hash; } - + +static void calc_diff(struct work *work, int known); + static void gen_gbt_work(struct pool *pool, struct work *work) { unsigned char *merkleroot; @@ -1508,19 +1510,35 @@ static void gen_gbt_work(struct pool *pool, struct work *work) merkleroot = __gbt_merkleroot(pool); memcpy(work->data, &pool->gbt_version, 4); hex2bin(work->data + 4, pool->previousblockhash, 32); - memcpy(work->data + 4 + 32, merkleroot, 32); memcpy(work->data + 4 + 32 + 32, &pool->curtime, 4); hex2bin(work->data + 4 + 32 + 32 + 4, pool->gbt_bits, 4); - memset(work->data + 4 + 32 + 32 + 4 + 4, 0, 4); /* nonce */ + + hex2bin(work->target, pool->gbt_target, 32); mutex_unlock(&pool->gbt_lock); + memcpy(work->data + 4 + 32, merkleroot, 32); + memset(work->data + 4 + 32 + 32 + 4 + 4, 0, 4); /* nonce */ + + hex2bin(work->data + 4 + 32 + 32 + 4 + 4 + 4, "000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000", 48); + hex2bin(work->hash1, "00000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000010000", 64); + if (opt_debug) { - char *header = bin2hex(work->data, 4 + 32 + 32 + 4 + 4 + 4); + char *header = bin2hex(work->data, 128); applog(LOG_DEBUG, "Generated GBT header %s", header); free(header); } + local_work++; + work->pool = pool; + work->gbt = true; + work->id = total_work++; + work->longpoll = false; + work->getwork_mode = GETWORK_MODE_GBT; + work->work_block = work_block; + calc_diff(work, 0); + gettimeofday(&work->tv_staged, NULL); + free(merkleroot); } diff --git a/miner.h b/miner.h index 6645f17a..e165bcbf 100644 --- a/miner.h +++ b/miner.h @@ -909,6 +909,7 @@ struct pool { #define GETWORK_MODE_LP 'L' #define GETWORK_MODE_BENCHMARK 'B' #define GETWORK_MODE_STRATUM 'S' +#define GETWORK_MODE_GBT 'G' struct work { unsigned char data[128]; From 5acb182ec1370dbea2035d597239b84a1849d154 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 4 Nov 2012 02:07:45 +1100 Subject: [PATCH 15/54] Hook into various places to generate GBT work where appropriate. --- cgminer.c | 55 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/cgminer.c b/cgminer.c index 04b21da1..eb34cd0c 100644 --- a/cgminer.c +++ b/cgminer.c @@ -3028,6 +3028,19 @@ retry: } if (pool->has_gbt) { +#if 0 + while (pool->idle) { + struct pool *altpool = select_pool(true); + + sleep(5); + if (altpool != pool) { + wc->pool = altpool; + inc_queued(altpool); + dec_queued(pool); + goto retry; + } + } +#endif ret_work = make_work(); gen_gbt_work(pool, ret_work); if (unlikely(!stage_work(ret_work))) { @@ -4951,7 +4964,17 @@ static bool reuse_work(struct work *work, struct pool *pool) if (!pool->stratum_active) return false; applog(LOG_DEBUG, "Reusing stratum work"); - gen_stratum_work(pool, work);; + gen_stratum_work(pool, work); + return true; + } + + if (pool->has_gbt) { +#if 0 + if (pool->idle) + return false; +#endif + applog(LOG_DEBUG, "Reusing GBT work"); + gen_gbt_work(pool, work); return true; } @@ -5602,7 +5625,7 @@ static struct pool *select_longpoll_pool(struct pool *cp) { int i; - if (cp->hdr_path) + if (cp->hdr_path || cp->has_gbt) return cp; for (i = 0; i < total_pools; i++) { struct pool *pool = pools[i]; @@ -5637,6 +5660,8 @@ static void *longpoll_thread(void *userdata) struct timeval start, reply, end; CURL *curl = NULL; int failures = 0; + char lpreq[1024]; + char *lp_url; int rolltime; curl = curl_easy_init(); @@ -5660,10 +5685,21 @@ retry_pool: wait_lpcurrent(cp); - if (cp == pool) - applog(LOG_WARNING, "Long-polling activated for %s", pool->lp_url); - else - applog(LOG_WARNING, "Long-polling activated for pool %s via %s", cp->rpc_url, pool->lp_url); + if (pool->has_gbt) { + sprintf(lpreq, "{\"id\": 0, \"method\": \"getblocktemplate\", \"params\": " + "[{\"capabilities\": [\"coinbasetxn\", \"workid\", \"coinbase/append\"], " + "\"longpollid\": \"%s\"}]}\n", pool->longpollid); + lp_url = pool->rpc_url; + applog(LOG_WARNING, "GBT longpoll ID activated for %s", lp_url); + } else { + strcpy(lpreq, getwork_req); + + lp_url = pool->lp_url; + if (cp == pool) + applog(LOG_WARNING, "Long-polling activated for %s", lp_url); + else + applog(LOG_WARNING, "Long-polling activated for pool %s via %s", cp->rpc_url, lp_url); + } while (42) { json_t *val, *soval; @@ -5677,9 +5713,8 @@ retry_pool: * so always establish a fresh connection instead of relying on * a persistent one. */ curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1); - val = json_rpc_call(curl, pool->lp_url, pool->rpc_userpass, - pool->rpc_req, false, true, &rolltime, - pool, false); + val = json_rpc_call(curl, lp_url, pool->rpc_userpass, + lpreq, false, true, &rolltime, pool, false); gettimeofday(&reply, NULL); @@ -5701,7 +5736,7 @@ retry_pool: if (end.tv_sec - start.tv_sec > 30) continue; if (failures == 1) - applog(LOG_WARNING, "longpoll failed for %s, retrying every 30s", pool->lp_url); + applog(LOG_WARNING, "longpoll failed for %s, retrying every 30s", lp_url); sleep(30); } if (pool != cp) { From c5c5fb82738093e682b769258a985c1339a4131b Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 4 Nov 2012 08:35:50 +1100 Subject: [PATCH 16/54] Store all the transaction hashes in pool->txn_hashes instead of separating txn0 and correct generation of merkle root, fixing memory overwrites. --- cgminer.c | 59 +++++++++++-------------------------------------------- miner.h | 2 -- 2 files changed, 12 insertions(+), 49 deletions(-) diff --git a/cgminer.c b/cgminer.c index eb34cd0c..518324c0 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1391,12 +1391,9 @@ static void gen_hash(unsigned char *data, unsigned char *hash, int len); static bool __build_gbt_txns(struct pool *pool, json_t *res_val) { json_t *txn_array; - const char *txn0; bool ret = false; int i, cal_len; - free(pool->txn0); - pool->txn0 = NULL; free(pool->txn_hashes); pool->txn_hashes = NULL; pool->gbt_txns = 0; @@ -1410,21 +1407,11 @@ static bool __build_gbt_txns(struct pool *pool, json_t *res_val) if (!pool->gbt_txns) goto out; - txn0 = json_string_value(json_object_get(json_array_get(txn_array, 0), "data")); - pool->txn0_len = strlen(txn0) / 2; - cal_len = pool->txn0_len; - if (cal_len % 4) - cal_len += 4 - (cal_len % 4); - pool->txn0 = calloc(cal_len , 1); - if (unlikely(!pool->txn0)) - quit(1, "Failed to calloc pool->txn0"); - if (!hex2bin(pool->txn0, txn0, pool->txn0_len)) - quit(1, "Failed to hex2bin txn0"); - pool->txn_hashes = calloc(32 * pool->gbt_txns, 1); + pool->txn_hashes = calloc(32 * (pool->gbt_txns + 1), 1); if (unlikely(!pool->txn_hashes)) quit(1, "Failed to calloc txn_hashes in __build_gbt_txns"); - for (i = 1; i < pool->gbt_txns; i++) { + for (i = 0; i < pool->gbt_txns; i++) { json_t *txn_val = json_object_get(json_array_get(txn_array, i), "data"); const char *txn = json_string_value(txn_val); int txn_len = strlen(txn); @@ -1439,7 +1426,7 @@ static bool __build_gbt_txns(struct pool *pool, json_t *res_val) if (unlikely(!hex2bin(txn_bin, txn, txn_len / 2))) quit(1, "Failed to hex2bin txn_bin"); - gen_hash(txn_bin, pool->txn_hashes + (32 * (i - 1)), txn_len); + gen_hash(txn_bin, pool->txn_hashes + (32 * i), txn_len); free(txn_bin); } out: @@ -1448,44 +1435,22 @@ out: static unsigned char *__gbt_merkleroot(struct pool *pool) { - unsigned char *merkles, *txn0, *merkle_hash; - int i, txns, cal_len; - - if (!pool->gbt_txns) { - pool->txn0 = (unsigned char *)strdup((const char *)pool->gbt_coinbase); - pool->txn0_len = pool->coinbase_len; - } - - cal_len = pool->coinbase_len + pool->txn0_len; - if (cal_len % 4) - cal_len += 4 - (cal_len % 4); - txn0 = calloc(cal_len, 1); - if (unlikely(!txn0)) - quit(1, "Failed to calloc txn0hash"); - - memcpy(txn0, pool->gbt_coinbase, pool->coinbase_len); - memcpy(txn0 + pool->coinbase_len, pool->txn0, pool->txn0_len); + unsigned char *merkle_hash; + int i, txns; - cal_len = 32 + (32 * pool->gbt_txns); - merkles = calloc(cal_len, 1); - if (unlikely(!merkles)) - quit(1, "Failed to calloc merkles in __gbt_merkleroot"); + merkle_hash = calloc(32 * (pool->gbt_txns + 2), 1); + if (unlikely(!merkle_hash)) + quit(1, "Failed to calloc merkle_hash in __gbt_merkleroot"); - gen_hash(txn0, merkles, pool->coinbase_len + pool->txn0_len); - free(txn0); + gen_hash(pool->gbt_coinbase, merkle_hash, pool->coinbase_len); if (pool->gbt_txns > 1) - memcpy(merkles + 32, pool->txn_hashes, (pool->gbt_txns - 1) * 32); - - cal_len = (pool->gbt_txns + 1) * 32; - merkle_hash = calloc(cal_len, 1); - if (unlikely(!merkle_hash)) - quit(1, "Failed to calloc merkle_hash in __gbt_merkleroot"); + memcpy(merkle_hash + 32, pool->txn_hashes, pool->gbt_txns * 32); txns = pool->gbt_txns + 1; while (txns > 1) { if (txns % 2) { - memcpy(&merkles[txns * 32], &merkles[(txns - 1) * 32], 32); + memcpy(&merkle_hash[txns * 32], &merkle_hash[(txns - 1) * 32], 32); txns++; } for (i = 0; i < txns; i += 2){ @@ -1517,6 +1482,7 @@ static void gen_gbt_work(struct pool *pool, struct work *work) mutex_unlock(&pool->gbt_lock); memcpy(work->data + 4 + 32, merkleroot, 32); + free(merkleroot); memset(work->data + 4 + 32 + 32 + 4 + 4, 0, 4); /* nonce */ hex2bin(work->data + 4 + 32 + 32 + 4 + 4 + 4, "000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000", 48); @@ -1539,7 +1505,6 @@ static void gen_gbt_work(struct pool *pool, struct work *work) calc_diff(work, 0); gettimeofday(&work->tv_staged, NULL); - free(merkleroot); } static bool gbt_decode(struct pool *pool, json_t *res_val) diff --git a/miner.h b/miner.h index e165bcbf..adb3ae5d 100644 --- a/miner.h +++ b/miner.h @@ -897,10 +897,8 @@ struct pool { bool gbt_submitold; char *gbt_bits; unsigned char *gbt_coinbase; - unsigned char *txn0; unsigned char *txn_hashes; int gbt_txns; - int txn0_len; int coinbase_len; }; From 914e88bbad25bb147b3b53f9263fcdafcf1c294e Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 4 Nov 2012 08:46:58 +1100 Subject: [PATCH 17/54] Skip trying to decipher LP url if we have GBT support. --- cgminer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index 518324c0..dc5682f3 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1504,7 +1504,6 @@ static void gen_gbt_work(struct pool *pool, struct work *work) work->work_block = work_block; calc_diff(work, 0); gettimeofday(&work->tv_staged, NULL); - } static bool gbt_decode(struct pool *pool, json_t *res_val) @@ -4778,7 +4777,7 @@ retry_stratum: } json_decref(val); - if (pool->lp_url) + if (pool->lp_url || pool->has_gbt) goto out; /* Decipher the longpoll URL, if any, and store it in ->lp_url */ From 59087a5d77aa8b1001e0245ab8e8b1155e8bb159 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 4 Nov 2012 08:59:00 +1100 Subject: [PATCH 18/54] Use same string for debug as for submission and make string larger to cope with future GBT messages. --- cgminer.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/cgminer.c b/cgminer.c index dc5682f3..598cf9f7 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2258,7 +2258,7 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit) { char *hexstr = NULL; json_t *val, *res, *err; - char s[345], sd[345]; + char s[1024]; bool rc = false; int thr_id = work->thr_id; struct cgpu_info *cgpu = thr_info[thr_id].cgpu; @@ -2279,14 +2279,9 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit) hexstr = bin2hex(work->data, sizeof(work->data)); /* build JSON-RPC request */ - sprintf(s, - "{\"method\": \"getwork\", \"params\": [ \"%s\" ], \"id\":1}\r\n", - hexstr); - sprintf(sd, - "{\"method\": \"getwork\", \"params\": [ \"%s\" ], \"id\":1}", - hexstr); - - applog(LOG_DEBUG, "DBG: sending %s submit RPC call: %s", pool->rpc_url, sd); + sprintf(s, "{\"method\": \"getwork\", \"params\": [ \"%s\" ], \"id\":1}", hexstr); + applog(LOG_DEBUG, "DBG: sending %s submit RPC call: %s", pool->rpc_url, s); + strcat(s, "\n"); gettimeofday(&tv_submit, NULL); /* issue JSON-RPC request */ From 6b34faf83c8a8a3877da825d9f22e698acd87e50 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 4 Nov 2012 10:24:09 +1100 Subject: [PATCH 19/54] Construct block for submission when using GBT. --- cgminer.c | 18 +++++++++++++++--- miner.h | 1 + 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/cgminer.c b/cgminer.c index 598cf9f7..fc501fe3 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1469,6 +1469,7 @@ static void calc_diff(struct work *work, int known); static void gen_gbt_work(struct pool *pool, struct work *work) { unsigned char *merkleroot; + char *cbhex; mutex_lock(&pool->gbt_lock); __build_gbt_coinbase(pool); @@ -1477,8 +1478,10 @@ static void gen_gbt_work(struct pool *pool, struct work *work) hex2bin(work->data + 4, pool->previousblockhash, 32); memcpy(work->data + 4 + 32 + 32, &pool->curtime, 4); hex2bin(work->data + 4 + 32 + 32 + 4, pool->gbt_bits, 4); - hex2bin(work->target, pool->gbt_target, 32); + cbhex = bin2hex(pool->gbt_coinbase, pool->coinbase_len); + sprintf(work->gbt_coinbase, "%s", cbhex); + free(cbhex); mutex_unlock(&pool->gbt_lock); memcpy(work->data + 4 + 32, merkleroot, 32); @@ -2279,8 +2282,17 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit) hexstr = bin2hex(work->data, sizeof(work->data)); /* build JSON-RPC request */ - sprintf(s, "{\"method\": \"getwork\", \"params\": [ \"%s\" ], \"id\":1}", hexstr); - applog(LOG_DEBUG, "DBG: sending %s submit RPC call: %s", pool->rpc_url, s); + if (work->gbt) { + char gbt_block[512], *header; + + header = bin2hex(work->data, 80); + sprintf(gbt_block, "%s0%s", header, work->gbt_coinbase); + free(header); + + sprintf(s, "{\"id\": 0, \"method\": \"submitblock\", \"params\": [\"%s\"]}", gbt_block); + } else + sprintf(s, "{\"method\": \"getwork\", \"params\": [ \"%s\" ], \"id\":1}", hexstr); + applog(LOG_WARNING, "DBG: sending %s submit RPC call: %s", pool->rpc_url, s); strcat(s, "\n"); gettimeofday(&tv_submit, NULL); diff --git a/miner.h b/miner.h index adb3ae5d..1c505bc7 100644 --- a/miner.h +++ b/miner.h @@ -946,6 +946,7 @@ struct work { int sdiff; bool gbt; + char gbt_coinbase[292]; unsigned int work_block; int id; From 2914a5eddfe879888f6a0a26ca6e17963a22c874 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 4 Nov 2012 12:18:59 +1100 Subject: [PATCH 20/54] Target and prevblockhash need to be reversed from GBT variables. --- cgminer.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cgminer.c b/cgminer.c index fc501fe3..ef23e63c 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1468,17 +1468,19 @@ static void calc_diff(struct work *work, int known); static void gen_gbt_work(struct pool *pool, struct work *work) { - unsigned char *merkleroot; + unsigned char *merkleroot, hash_swap[32]; char *cbhex; mutex_lock(&pool->gbt_lock); __build_gbt_coinbase(pool); merkleroot = __gbt_merkleroot(pool); memcpy(work->data, &pool->gbt_version, 4); - hex2bin(work->data + 4, pool->previousblockhash, 32); + hex2bin(hash_swap, pool->previousblockhash, 32); + swap256(work->data + 4, hash_swap); memcpy(work->data + 4 + 32 + 32, &pool->curtime, 4); hex2bin(work->data + 4 + 32 + 32 + 4, pool->gbt_bits, 4); - hex2bin(work->target, pool->gbt_target, 32); + hex2bin(hash_swap, pool->gbt_target, 32); + swap256(work->target, hash_swap); cbhex = bin2hex(pool->gbt_coinbase, pool->coinbase_len); sprintf(work->gbt_coinbase, "%s", cbhex); free(cbhex); From cdc3c8779ad451e099c2a6b308ce521383735023 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 4 Nov 2012 14:58:24 +1100 Subject: [PATCH 21/54] 32 bit hex encoded variables should be in LE with GBT. --- cgminer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index ef23e63c..aedc1a50 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1560,8 +1560,8 @@ static bool gbt_decode(struct pool *pool, json_t *res_val) pool->coinbasetxn = strdup(coinbasetxn); pool->longpollid = strdup(longpollid); pool->gbt_expires = expires; - pool->gbt_version = htobe32(version); - pool->curtime = htobe32(curtime); + pool->gbt_version = htole32(version); + pool->curtime = htole32(curtime); pool->gbt_submitold = submitold; pool->gbt_bits = strdup(bits); __build_gbt_txns(pool, res_val); From 889ed23934dfa95154749b410b8307dae14c366a Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 4 Nov 2012 15:28:13 +1100 Subject: [PATCH 22/54] Store the fixed size entries as static variables in GBT in binary form, byteswapping as is required. --- cgminer.c | 32 ++++++++++++++++++++------------ miner.h | 6 +++--- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/cgminer.c b/cgminer.c index aedc1a50..5ba3dabf 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1468,19 +1468,20 @@ static void calc_diff(struct work *work, int known); static void gen_gbt_work(struct pool *pool, struct work *work) { - unsigned char *merkleroot, hash_swap[32]; + unsigned char *merkleroot; char *cbhex; mutex_lock(&pool->gbt_lock); __build_gbt_coinbase(pool); merkleroot = __gbt_merkleroot(pool); + memcpy(work->data, &pool->gbt_version, 4); - hex2bin(hash_swap, pool->previousblockhash, 32); - swap256(work->data + 4, hash_swap); + memcpy(work->data + 4, pool->previousblockhash, 32); memcpy(work->data + 4 + 32 + 32, &pool->curtime, 4); - hex2bin(work->data + 4 + 32 + 32 + 4, pool->gbt_bits, 4); - hex2bin(hash_swap, pool->gbt_target, 32); - swap256(work->target, hash_swap); + memcpy(work->data + 4 + 32 + 32 + 4, &pool->gbt_bits, 4); + + memcpy(work->target, pool->gbt_target, 32); + cbhex = bin2hex(pool->gbt_coinbase, pool->coinbase_len); sprintf(work->gbt_coinbase, "%s", cbhex); free(cbhex); @@ -1517,6 +1518,8 @@ static bool gbt_decode(struct pool *pool, json_t *res_val) const char *target; const char *coinbasetxn; const char *longpollid; + unsigned char hash_swap[32]; + uint32_t h32swap; int expires; int version; int curtime; @@ -1550,20 +1553,25 @@ static bool gbt_decode(struct pool *pool, json_t *res_val) applog(LOG_DEBUG, "bits: %s", bits); mutex_lock(&pool->gbt_lock); - free(pool->previousblockhash); - free(pool->gbt_target); free(pool->coinbasetxn); free(pool->longpollid); - free(pool->gbt_bits); - pool->previousblockhash = strdup(previousblockhash); - pool->gbt_target = strdup(target); pool->coinbasetxn = strdup(coinbasetxn); pool->longpollid = strdup(longpollid); + + hex2bin(hash_swap, previousblockhash, 32); + swab256(pool->previousblockhash, hash_swap); + + hex2bin(hash_swap, target, 32); + swab256(pool->gbt_target, hash_swap); + pool->gbt_expires = expires; pool->gbt_version = htole32(version); pool->curtime = htole32(curtime); pool->gbt_submitold = submitold; - pool->gbt_bits = strdup(bits); + + hex2bin((unsigned char *)&h32swap, bits, 4); + pool->gbt_bits = swab32(h32swap); + __build_gbt_txns(pool, res_val); mutex_unlock(&pool->gbt_lock); diff --git a/miner.h b/miner.h index 1c505bc7..9a2ef2d9 100644 --- a/miner.h +++ b/miner.h @@ -887,15 +887,15 @@ struct pool { /* GBT variables */ bool has_gbt; pthread_mutex_t gbt_lock; - char *previousblockhash; - char *gbt_target; + unsigned char previousblockhash[32]; + unsigned char gbt_target[32]; char *coinbasetxn; char *longpollid; int gbt_expires; uint32_t gbt_version; uint32_t curtime; bool gbt_submitold; - char *gbt_bits; + uint32_t gbt_bits; unsigned char *gbt_coinbase; unsigned char *txn_hashes; int gbt_txns; From 88b6f7924c8bbc9eb52c45b4b34293b97bd58f14 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 4 Nov 2012 18:01:09 +1100 Subject: [PATCH 23/54] Make gbt_coinbase large enough for submissions, swap bytes correctly to make a header from GBT and encode the number of transactions in share submission. --- cgminer.c | 33 ++++++++++++++++++++++++--------- miner.h | 3 ++- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/cgminer.c b/cgminer.c index 5ba3dabf..51f83b97 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1485,6 +1485,9 @@ static void gen_gbt_work(struct pool *pool, struct work *work) cbhex = bin2hex(pool->gbt_coinbase, pool->coinbase_len); sprintf(work->gbt_coinbase, "%s", cbhex); free(cbhex); + + /* For encoding the block data on submission */ + work->gbt_txns = pool->gbt_txns + 1; mutex_unlock(&pool->gbt_lock); memcpy(work->data + 4 + 32, merkleroot, 32); @@ -1498,6 +1501,7 @@ static void gen_gbt_work(struct pool *pool, struct work *work) char *header = bin2hex(work->data, 128); applog(LOG_DEBUG, "Generated GBT header %s", header); + applog(LOG_DEBUG, "Work coinbase %s", work->gbt_coinbase); free(header); } @@ -1519,7 +1523,6 @@ static bool gbt_decode(struct pool *pool, json_t *res_val) const char *coinbasetxn; const char *longpollid; unsigned char hash_swap[32]; - uint32_t h32swap; int expires; int version; int curtime; @@ -1559,18 +1562,17 @@ static bool gbt_decode(struct pool *pool, json_t *res_val) pool->longpollid = strdup(longpollid); hex2bin(hash_swap, previousblockhash, 32); - swab256(pool->previousblockhash, hash_swap); + swap256(pool->previousblockhash, hash_swap); hex2bin(hash_swap, target, 32); - swab256(pool->gbt_target, hash_swap); + swap256(pool->gbt_target, hash_swap); pool->gbt_expires = expires; - pool->gbt_version = htole32(version); - pool->curtime = htole32(curtime); + pool->gbt_version = htobe32(version); + pool->curtime = htobe32(curtime); pool->gbt_submitold = submitold; - hex2bin((unsigned char *)&h32swap, bits, 4); - pool->gbt_bits = swab32(h32swap); + hex2bin((unsigned char *)&pool->gbt_bits, bits, 4); __build_gbt_txns(pool, res_val); mutex_unlock(&pool->gbt_lock); @@ -2293,10 +2295,23 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit) /* build JSON-RPC request */ if (work->gbt) { - char gbt_block[512], *header; + char gbt_block[512], varint[10] = "", *header; + + if (work->gbt_txns < 0xfd) { + uint8_t val = work->gbt_txns; + + sprintf(varint, "%02x", val); + } else if (work->gbt_txns <= 0xffff) { + uint16_t val = htole16(work->gbt_txns); + sprintf(varint, "fd%04x", val); + } else if ((unsigned int)work->gbt_txns <= 0xffffffff) { + uint32_t val = htole32(work->gbt_txns); + + sprintf(varint, "fe%08x", val); + } header = bin2hex(work->data, 80); - sprintf(gbt_block, "%s0%s", header, work->gbt_coinbase); + sprintf(gbt_block, "%s%s%s", header, varint, work->gbt_coinbase); free(header); sprintf(s, "{\"id\": 0, \"method\": \"submitblock\", \"params\": [\"%s\"]}", gbt_block); diff --git a/miner.h b/miner.h index 9a2ef2d9..0f37b873 100644 --- a/miner.h +++ b/miner.h @@ -946,7 +946,8 @@ struct work { int sdiff; bool gbt; - char gbt_coinbase[292]; + char gbt_coinbase[512]; + int gbt_txns; unsigned int work_block; int id; From cb6f0340cd19a048ac7bbd4554ffed2646e15ecc Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Nov 2012 08:27:20 +1100 Subject: [PATCH 24/54] Build varint correctly for share submission and sleep 5 seconds before retrying submit. --- cgminer.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/cgminer.c b/cgminer.c index 51f83b97..962e1f29 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2295,26 +2295,43 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit) /* build JSON-RPC request */ if (work->gbt) { - char gbt_block[512], varint[10] = "", *header; + char gbt_block[512], *varint, *header; + unsigned char data[80]; + int i; + + for (i = 0; i < 80 / 4; i++) { + uint32_t *src32, *dst32; + + src32 = (uint32_t *)&work->data[i * 4]; + dst32 = (uint32_t *)&data[i * 4]; + *dst32 = swab32(*src32); + } + header = bin2hex(data, 80); + sprintf(gbt_block, "%s", header); + free(header); + applog(LOG_WARNING, "%d transactions", work->gbt_txns); if (work->gbt_txns < 0xfd) { uint8_t val = work->gbt_txns; - sprintf(varint, "%02x", val); + varint = bin2hex((const unsigned char *)&val, 1); } else if (work->gbt_txns <= 0xffff) { uint16_t val = htole16(work->gbt_txns); - sprintf(varint, "fd%04x", val); - } else if ((unsigned int)work->gbt_txns <= 0xffffffff) { + strcat(gbt_block, "fd"); + varint = bin2hex((const unsigned char *)&val, 2); + } else { uint32_t val = htole32(work->gbt_txns); - sprintf(varint, "fe%08x", val); + strcat(gbt_block, "fe"); + varint = bin2hex((const unsigned char *)&val, 4); } - header = bin2hex(work->data, 80); - sprintf(gbt_block, "%s%s%s", header, varint, work->gbt_coinbase); - free(header); + applog(LOG_WARNING, "Varint %s", varint); + strcat(gbt_block, varint); + free(varint); + strcat(gbt_block, work->gbt_coinbase); - sprintf(s, "{\"id\": 0, \"method\": \"submitblock\", \"params\": [\"%s\"]}", gbt_block); + sprintf(s, "{\"id\": 0, \"method\": \"submitblock\", \"params\": [\"%s\", {}]}", gbt_block); } else sprintf(s, "{\"method\": \"getwork\", \"params\": [ \"%s\" ], \"id\":1}", hexstr); applog(LOG_WARNING, "DBG: sending %s submit RPC call: %s", pool->rpc_url, s); @@ -2331,6 +2348,7 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit) pool->remotefail_occasions++; applog(LOG_WARNING, "Pool %d communication failure, caching submissions", pool->pool_no); } + sleep(5); goto out; } else if (pool_tclear(pool, &pool->submit_fail)) applog(LOG_WARNING, "Pool %d communication resumed, submitting work", pool->pool_no); From bd384883da63cbba4447fba5f9e21ac2fc101b6a Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Nov 2012 08:39:33 +1100 Subject: [PATCH 25/54] Remove varint display debugging. --- cgminer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 962e1f29..7c2b550a 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2326,7 +2326,6 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit) strcat(gbt_block, "fe"); varint = bin2hex((const unsigned char *)&val, 4); } - applog(LOG_WARNING, "Varint %s", varint); strcat(gbt_block, varint); free(varint); strcat(gbt_block, work->gbt_coinbase); From 611c3164dc4b971a89273956f9bff3e0c77a5bf5 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Nov 2012 10:55:55 +1100 Subject: [PATCH 26/54] Remove txn size debugging and enlarge gbt block string to prevent overflow. --- cgminer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index 7c2b550a..60330739 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2295,7 +2295,7 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit) /* build JSON-RPC request */ if (work->gbt) { - char gbt_block[512], *varint, *header; + char gbt_block[1024], *varint, *header; unsigned char data[80]; int i; @@ -2310,7 +2310,6 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit) sprintf(gbt_block, "%s", header); free(header); - applog(LOG_WARNING, "%d transactions", work->gbt_txns); if (work->gbt_txns < 0xfd) { uint8_t val = work->gbt_txns; From 734f3d1c5461607ad8efd6125c50cc0b7d3506c3 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Nov 2012 11:49:22 +1100 Subject: [PATCH 27/54] Insert the extra nonce and remaining data in the correct position in the coinbase. --- cgminer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index 60330739..d7049f69 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1374,10 +1374,11 @@ static void __build_gbt_coinbase(struct pool *pool) coinbase = calloc(cal_len, 1); hex2bin(coinbase, pool->coinbasetxn, 42); extra_len = (uint8_t *)(coinbase + 41); + hex2bin(coinbase + 42, pool->coinbasetxn + 84, *extra_len); + memcpy(coinbase + 42 + *extra_len, &pool->nonce2, 4); *extra_len += 4; - hex2bin(coinbase + 42, pool->coinbasetxn + 84, cbt_len - 42); + hex2bin(coinbase + 42 + *extra_len, pool->coinbasetxn + 84 + (*extra_len * 2), cbt_len - *extra_len - 42); pool->nonce2++; - memcpy(coinbase + cbt_len, &pool->nonce2, 4); free(pool->gbt_coinbase); pool->gbt_coinbase = coinbase; } From 0ba5f0f94b1e671b3892857afe66b05180727651 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Nov 2012 14:02:43 +1100 Subject: [PATCH 28/54] Use a standard function for flipping bytes. --- cgminer.c | 8 +------- miner.h | 10 ++++++++++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/cgminer.c b/cgminer.c index d7049f69..bc86c9c3 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2300,13 +2300,7 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit) unsigned char data[80]; int i; - for (i = 0; i < 80 / 4; i++) { - uint32_t *src32, *dst32; - - src32 = (uint32_t *)&work->data[i * 4]; - dst32 = (uint32_t *)&data[i * 4]; - *dst32 = swab32(*src32); - } + flip256(data, work->data); header = bin2hex(data, 80); sprintf(gbt_block, "%s", header); free(header); diff --git a/miner.h b/miner.h index 0f37b873..91b0300f 100644 --- a/miner.h +++ b/miner.h @@ -544,6 +544,16 @@ static inline void swab256(void *dest_p, const void *src_p) dest[7] = swab32(src[0]); } +static inline void flip256(void *dest_p, const void *src_p) +{ + uint32_t *dest = dest_p; + const uint32_t *src = src_p; + int i; + + for (i = 0; i < 8; i++) + dest[i] = swab32(src[i]); +} + extern void quit(int status, const char *format, ...); static inline void mutex_lock(pthread_mutex_t *lock) From 8bc677a6ca856d0476d10dd84194dfaaee2cb981 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Nov 2012 14:44:58 +1100 Subject: [PATCH 29/54] Calculate midstate for gbt work and remove now unused variable. --- cgminer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index bc86c9c3..fab5a1f2 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1506,6 +1506,7 @@ static void gen_gbt_work(struct pool *pool, struct work *work) free(header); } + calc_midstate(work); local_work++; work->pool = pool; work->gbt = true; @@ -2298,7 +2299,6 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit) if (work->gbt) { char gbt_block[1024], *varint, *header; unsigned char data[80]; - int i; flip256(data, work->data); header = bin2hex(data, 80); From a4e78be1ed8bf6a698f29e007f043c16fad63e3f Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Nov 2012 14:56:57 +1100 Subject: [PATCH 30/54] Flip all 80 bytes in the flip function which was wrongly named flip256 for its purpose. --- cgminer.c | 2 +- miner.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cgminer.c b/cgminer.c index fab5a1f2..06b9c00d 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2300,7 +2300,7 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit) char gbt_block[1024], *varint, *header; unsigned char data[80]; - flip256(data, work->data); + flip80(data, work->data); header = bin2hex(data, 80); sprintf(gbt_block, "%s", header); free(header); diff --git a/miner.h b/miner.h index 91b0300f..2a19ab80 100644 --- a/miner.h +++ b/miner.h @@ -544,13 +544,13 @@ static inline void swab256(void *dest_p, const void *src_p) dest[7] = swab32(src[0]); } -static inline void flip256(void *dest_p, const void *src_p) +static inline void flip80(void *dest_p, const void *src_p) { uint32_t *dest = dest_p; const uint32_t *src = src_p; int i; - for (i = 0; i < 8; i++) + for (i = 0; i < 20; i++) dest[i] = swab32(src[i]); } From 14c436ee1f6349a0b4d50a11014403f4d84c81a5 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Nov 2012 15:28:07 +1100 Subject: [PATCH 31/54] Use correct length for offsetting extra nonce and remaining data. --- cgminer.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cgminer.c b/cgminer.c index 06b9c00d..02304fcd 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1361,8 +1361,8 @@ static void calc_midstate(struct work *work) * entered under gbt_lock */ static void __build_gbt_coinbase(struct pool *pool) { + int cbt_len, cal_len, orig_len; unsigned char *coinbase; - int cbt_len, cal_len; uint8_t *extra_len; cbt_len = strlen(pool->coinbasetxn) / 2; @@ -1374,10 +1374,11 @@ static void __build_gbt_coinbase(struct pool *pool) coinbase = calloc(cal_len, 1); hex2bin(coinbase, pool->coinbasetxn, 42); extra_len = (uint8_t *)(coinbase + 41); - hex2bin(coinbase + 42, pool->coinbasetxn + 84, *extra_len); - memcpy(coinbase + 42 + *extra_len, &pool->nonce2, 4); + orig_len = *extra_len; + hex2bin(coinbase + 42, pool->coinbasetxn + 84, orig_len); + memcpy(coinbase + 42 + orig_len, &pool->nonce2, 4); *extra_len += 4; - hex2bin(coinbase + 42 + *extra_len, pool->coinbasetxn + 84 + (*extra_len * 2), cbt_len - *extra_len - 42); + hex2bin(coinbase + 42 + *extra_len, pool->coinbasetxn + 84 + (orig_len * 2), cbt_len - orig_len - 42); pool->nonce2++; free(pool->gbt_coinbase); pool->gbt_coinbase = coinbase; From 85f400bf801482b5121802792f406a75ff7f4e76 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Nov 2012 15:57:47 +1100 Subject: [PATCH 32/54] Correct last few components of GBT block generation courtesy of Luke-jr. --- cgminer.c | 5 +++-- miner.h | 10 ++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index 02304fcd..0025684b 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1428,7 +1428,7 @@ static bool __build_gbt_txns(struct pool *pool, json_t *res_val) if (unlikely(!hex2bin(txn_bin, txn, txn_len / 2))) quit(1, "Failed to hex2bin txn_bin"); - gen_hash(txn_bin, pool->txn_hashes + (32 * i), txn_len); + gen_hash(txn_bin, pool->txn_hashes + (32 * i), txn_len / 2); free(txn_bin); } out: @@ -1446,7 +1446,7 @@ static unsigned char *__gbt_merkleroot(struct pool *pool) gen_hash(pool->gbt_coinbase, merkle_hash, pool->coinbase_len); - if (pool->gbt_txns > 1) + if (pool->gbt_txns) memcpy(merkle_hash + 32, pool->txn_hashes, pool->gbt_txns * 32); txns = pool->gbt_txns + 1; @@ -1493,6 +1493,7 @@ static void gen_gbt_work(struct pool *pool, struct work *work) mutex_unlock(&pool->gbt_lock); memcpy(work->data + 4 + 32, merkleroot, 32); + flip32(work->data + 4 + 32, merkleroot); free(merkleroot); memset(work->data + 4 + 32 + 32 + 4 + 4, 0, 4); /* nonce */ diff --git a/miner.h b/miner.h index 2a19ab80..ac4abf80 100644 --- a/miner.h +++ b/miner.h @@ -544,6 +544,16 @@ static inline void swab256(void *dest_p, const void *src_p) dest[7] = swab32(src[0]); } +static inline void flip32(void *dest_p, const void *src_p) +{ + uint32_t *dest = dest_p; + const uint32_t *src = src_p; + int i; + + for (i = 0; i < 8; i++) + dest[i] = swab32(src[i]); +} + static inline void flip80(void *dest_p, const void *src_p) { uint32_t *dest = dest_p; From 345e72e66eccd9d14d80117193235f4dc6e4890b Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Nov 2012 16:17:04 +1100 Subject: [PATCH 33/54] Allow the longpoll thread to start with GBT and only set the longpollid once. --- cgminer.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cgminer.c b/cgminer.c index 0025684b..57fff4c7 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1561,9 +1561,9 @@ static bool gbt_decode(struct pool *pool, json_t *res_val) mutex_lock(&pool->gbt_lock); free(pool->coinbasetxn); - free(pool->longpollid); pool->coinbasetxn = strdup(coinbasetxn); - pool->longpollid = strdup(longpollid); + if (!pool->longpollid) + pool->longpollid = strdup(longpollid); hex2bin(hash_swap, previousblockhash, 32); swap256(pool->previousblockhash, hash_swap); @@ -4822,7 +4822,7 @@ retry_stratum: } json_decref(val); - if (pool->lp_url || pool->has_gbt) + if (pool->lp_url) goto out; /* Decipher the longpoll URL, if any, and store it in ->lp_url */ @@ -6797,6 +6797,7 @@ int main(int argc, char *argv[]) for (i = 0; i < total_pools; i++) { struct pool *pool = pools[i]; if (pool_active(pool, false)) { + pool_tclear(pool, &pool->idle); if (!currentpool) currentpool = pool; applog(LOG_INFO, "Pool %d %s active", pool->pool_no, pool->rpc_url); From cc7c274543c1ebb7adbb0fbedd8cd3ded6ffb052 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Nov 2012 16:28:52 +1100 Subject: [PATCH 34/54] Manage appropriate response codes for share submission with GBT. --- cgminer.c | 7 ++++--- util.c | 3 +-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cgminer.c b/cgminer.c index 57fff4c7..eae7228f 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2131,7 +2131,7 @@ share_result(json_t *val, json_t *res, json_t *err, const struct work *work, struct pool *pool = work->pool; struct cgpu_info *cgpu = thr_info[work->thr_id].cgpu; - if (json_is_true(res)) { + if (json_is_true(res) || (work->gbt && json_is_null(res))) { cgpu->accepted++; total_accepted++; pool->accepted++; @@ -2189,7 +2189,8 @@ share_result(json_t *val, json_t *res, json_t *err, const struct work *work, else strcpy(where, ""); - res = json_object_get(val, "reject-reason"); + if (!work->gbt) + res = json_object_get(val, "reject-reason"); if (res) { const char *reasontmp = json_string_value(res); @@ -2329,7 +2330,7 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit) sprintf(s, "{\"id\": 0, \"method\": \"submitblock\", \"params\": [\"%s\", {}]}", gbt_block); } else sprintf(s, "{\"method\": \"getwork\", \"params\": [ \"%s\" ], \"id\":1}", hexstr); - applog(LOG_WARNING, "DBG: sending %s submit RPC call: %s", pool->rpc_url, s); + applog(LOG_DEBUG, "DBG: sending %s submit RPC call: %s", pool->rpc_url, s); strcat(s, "\n"); gettimeofday(&tv_submit, NULL); diff --git a/util.c b/util.c index 439c6035..072c5ce8 100644 --- a/util.c +++ b/util.c @@ -451,8 +451,7 @@ json_t *json_rpc_call(CURL *curl, const char *url, res_val = json_object_get(val, "result"); err_val = json_object_get(val, "error"); - if (!res_val || json_is_null(res_val) || - (err_val && !json_is_null(err_val))) { + if (!res_val ||(err_val && !json_is_null(err_val))) { char *s; if (err_val) From fc94e00fd194fcda3ff6615d91a76d0058942e3e Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Nov 2012 16:34:44 +1100 Subject: [PATCH 35/54] Update GBT longpollid every time we request a new longpoll. --- cgminer.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/cgminer.c b/cgminer.c index eae7228f..2571613c 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1562,8 +1562,8 @@ static bool gbt_decode(struct pool *pool, json_t *res_val) mutex_lock(&pool->gbt_lock); free(pool->coinbasetxn); pool->coinbasetxn = strdup(coinbasetxn); - if (!pool->longpollid) - pool->longpollid = strdup(longpollid); + free(pool->longpollid); + pool->longpollid = strdup(longpollid); hex2bin(hash_swap, previousblockhash, 32); swap256(pool->previousblockhash, hash_swap); @@ -3575,8 +3575,8 @@ static bool test_work_current(struct work *work) if (!work->stratum) { if (work->longpoll) { - applog(LOG_NOTICE, "LONGPOLL from pool %d detected new block", - work->pool->pool_no); + applog(LOG_NOTICE, "%sLONGPOLL from pool %d detected new block", + work->gbt ? "GBT " : "", work->pool->pool_no); work->longpoll = false; } else if (have_longpoll) applog(LOG_NOTICE, "New block detected on network before longpoll"); @@ -3587,8 +3587,8 @@ static bool test_work_current(struct work *work) } else if (work->longpoll) { work->longpoll = false; if (work->pool == current_pool()) { - applog(LOG_NOTICE, "LONGPOLL from pool %d requested work restart", - work->pool->pool_no); + applog(LOG_NOTICE, "%sLONGPOLL from pool %d requested work restart", + work->gbt ? "GBT " : "", work->pool->pool_no); work_block++; restart_threads(); } @@ -5696,9 +5696,6 @@ retry_pool: wait_lpcurrent(cp); if (pool->has_gbt) { - sprintf(lpreq, "{\"id\": 0, \"method\": \"getblocktemplate\", \"params\": " - "[{\"capabilities\": [\"coinbasetxn\", \"workid\", \"coinbase/append\"], " - "\"longpollid\": \"%s\"}]}\n", pool->longpollid); lp_url = pool->rpc_url; applog(LOG_WARNING, "GBT longpoll ID activated for %s", lp_url); } else { @@ -5718,6 +5715,16 @@ retry_pool: gettimeofday(&start, NULL); + /* Update the longpollid every time, but do it under lock to + * avoid races */ + if (pool->has_gbt) { + mutex_lock(&pool->gbt_lock); + sprintf(lpreq, "{\"id\": 0, \"method\": \"getblocktemplate\", \"params\": " + "[{\"capabilities\": [\"coinbasetxn\", \"workid\", \"coinbase/append\"], " + "\"longpollid\": \"%s\"}]}\n", pool->longpollid); + mutex_unlock(&pool->gbt_lock); + } + /* Longpoll connections can be persistent for a very long time * and any number of issues could have come up in the meantime * so always establish a fresh connection instead of relying on From f71b423080aa862c7ec08393835fc6e64eb3bbe2 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Nov 2012 16:48:19 +1100 Subject: [PATCH 36/54] Retrieve a new block template if more than 30 seconds has elapsed since the last one to keep the data current and test the pool is still alive. --- cgminer.c | 17 +++++++++++++++-- miner.h | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index 2571613c..3cbf306d 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1622,6 +1622,7 @@ static bool work_decode(struct pool *pool, struct work *work, json_t *val) if (pool->has_gbt) { if (unlikely(!gbt_decode(pool, res_val))) goto out; + gettimeofday(&pool->tv_template, NULL); work->gbt = true; ret = true; goto out; @@ -4713,7 +4714,10 @@ static bool pool_active(struct pool *pool, bool pinging) CURL *curl; int rolltime; - applog(LOG_INFO, "Testing pool %s", pool->rpc_url); + if (pool->has_gbt) + applog(LOG_DEBUG, "Retrieving block template from pool %s", pool->rpc_url); + else + applog(LOG_INFO, "Testing pool %s", pool->rpc_url); /* This is the central point we activate stratum when we can */ retry_stratum: @@ -5829,8 +5833,17 @@ static void *watchpool_thread(void __maybe_unused *userdata) if (pool->enabled == POOL_DISABLED || pool->has_stratum) continue; + /* Apart from longpollid comms, we retrieve a fresh + * template if more than 30 seconds has elapsed since + * the last one to keep the data current and as a test + * for when the pool dies. */ + if (!pool->idle && pool->has_gbt && now.tv_sec - pool->tv_template.tv_sec > 60) { + if (!pool_active(pool, true)) + pool_died(pool); + } + /* Test pool is idle once every minute */ - if (pool->idle && now.tv_sec - pool->tv_idle.tv_sec > 60) { + if (pool->idle && now.tv_sec - pool->tv_idle.tv_sec > 30) { gettimeofday(&pool->tv_idle, NULL); if (pool_active(pool, true) && pool_tclear(pool, &pool->idle)) pool_resus(pool); diff --git a/miner.h b/miner.h index ac4abf80..72bff3e2 100644 --- a/miner.h +++ b/miner.h @@ -920,6 +920,7 @@ struct pool { unsigned char *txn_hashes; int gbt_txns; int coinbase_len; + struct timeval tv_template; }; #define GETWORK_MODE_TESTPOOL 'T' From 10ea5fbf97de09997c322b8b16e0d10e257c6f68 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Nov 2012 16:57:48 +1100 Subject: [PATCH 37/54] Use existing pool submit_old bool from gbt data. --- cgminer.c | 2 +- miner.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index 3cbf306d..504ed242 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1574,7 +1574,7 @@ static bool gbt_decode(struct pool *pool, json_t *res_val) pool->gbt_expires = expires; pool->gbt_version = htobe32(version); pool->curtime = htobe32(curtime); - pool->gbt_submitold = submitold; + pool->submit_old = submitold; hex2bin((unsigned char *)&pool->gbt_bits, bits, 4); diff --git a/miner.h b/miner.h index 72bff3e2..b8676fd0 100644 --- a/miner.h +++ b/miner.h @@ -914,7 +914,6 @@ struct pool { int gbt_expires; uint32_t gbt_version; uint32_t curtime; - bool gbt_submitold; uint32_t gbt_bits; unsigned char *gbt_coinbase; unsigned char *txn_hashes; From 1321cb0e0d4f2ba2262e7b11a96d9defc62ca7b5 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Nov 2012 17:57:33 +1100 Subject: [PATCH 38/54] Generate a gbt work item from longpoll when required to set new block and message appropriately. --- cgminer.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index 504ed242..ab5657ef 100644 --- a/cgminer.c +++ b/cgminer.c @@ -5598,15 +5598,18 @@ static void convert_to_work(json_t *val, int rolltime, struct pool *pool, struct } work->pool = pool; work->rolltime = rolltime; - work->longpoll = true; memcpy(&(work->tv_getwork), tv_lp, sizeof(struct timeval)); memcpy(&(work->tv_getwork_reply), tv_lp_reply, sizeof(struct timeval)); - work->getwork_mode = GETWORK_MODE_LP; calc_diff(work, 0); if (pool->enabled == POOL_REJECTING) work->mandatory = true; + if (pool->has_gbt) + gen_gbt_work(pool, work); + work->longpoll = true; + work->getwork_mode = GETWORK_MODE_LP; + /* We'll be checking this work item twice, but we already know it's * from a new block so explicitly force the new block detection now * rather than waiting for it to hit the stage thread. This also From 275bb9c05ee6e6abc09f94df501e4394031b84d8 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Nov 2012 18:05:25 +1100 Subject: [PATCH 39/54] Change status window message for GBT connected pools versus LP. --- cgminer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index ab5657ef..50583311 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1846,8 +1846,9 @@ static void curses_print_status(void) mvwprintw(statuswin, 4, 0, " Connected to multiple pools with%s LP", have_longpoll ? "": "out"); } else { - mvwprintw(statuswin, 4, 0, " Connected to %s with%s LP as user %s", - pool->sockaddr_url, have_longpoll ? "": "out", pool->rpc_user); + mvwprintw(statuswin, 4, 0, " Connected to %s with%s %s as user %s", + pool->sockaddr_url, have_longpoll ? "": "out", + pool->has_gbt ? "GBT" : "LP", pool->rpc_user); } wclrtoeol(statuswin); mvwprintw(statuswin, 5, 0, " Block: %s... Started: %s Best share: %s ", current_hash, blocktime, best_share); From 0314081157f7c929f3e79c63bdbddc625cf3137a Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Nov 2012 22:12:27 +1100 Subject: [PATCH 40/54] Swab, don't just swap the bytes in the GBT target. --- cgminer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 50583311..201ab2b0 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1569,7 +1569,7 @@ static bool gbt_decode(struct pool *pool, json_t *res_val) swap256(pool->previousblockhash, hash_swap); hex2bin(hash_swap, target, 32); - swap256(pool->gbt_target, hash_swap); + swab256(pool->gbt_target, hash_swap); pool->gbt_expires = expires; pool->gbt_version = htobe32(version); From 0465fef5535e55c5284404e59192659b16bcadb0 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Nov 2012 23:22:36 +1100 Subject: [PATCH 41/54] Discard record of stratum shares sent and report lost shares on disconnection since they will never be reported back. --- cgminer.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/cgminer.c b/cgminer.c index 0ac54da5..9139412a 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4305,6 +4305,25 @@ out: static void pool_resus(struct pool *pool); +static void clear_stratum_shares(struct pool *pool) +{ + struct stratum_share *sshare, *tmpshare; + int cleared = 0; + + mutex_lock(&sshare_lock); + HASH_ITER(hh, stratum_shares, sshare, tmpshare) { + if (sshare->work.pool == pool) { + HASH_DEL(stratum_shares, sshare); + free(sshare); + cleared++; + } + } + mutex_unlock(&sshare_lock); + + if (cleared) + applog(LOG_WARNING, "Lost %d shares due to stratum disconnect on pool %d", cleared, pool->pool_no); +} + /* One stratum thread per pool that has stratum waits on the socket checking * for new messages and for the integrity of the socket connection. We reset * the connection based on the integrity of the receive side only as the send @@ -4341,6 +4360,11 @@ static void *stratum_thread(void *userdata) pool->getfail_occasions++; total_go++; + /* If the socket to our stratum pool disconnects, all + * tracked submitted shares are lost and we will leak + * the memory if we don't discard their records. */ + clear_stratum_shares(pool); + if (initiate_stratum(pool) && auth_stratum(pool)) continue; From ffb8a29abf5b403dca7fa67cf1a6d1443982da9c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Nov 2012 23:25:36 +1100 Subject: [PATCH 42/54] Count lost shares with stratum as submit stale lost. --- cgminer.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 9139412a..1d5691c8 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4320,8 +4320,11 @@ static void clear_stratum_shares(struct pool *pool) } mutex_unlock(&sshare_lock); - if (cleared) + if (cleared) { applog(LOG_WARNING, "Lost %d shares due to stratum disconnect on pool %d", cleared, pool->pool_no); + pool->stale_shares++; + total_stale++; + } } /* One stratum thread per pool that has stratum waits on the socket checking From e0157208abf83540a3fc7ce432e9870aa5fc1e24 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Nov 2012 23:44:00 +1100 Subject: [PATCH 43/54] Add management for dead GBT pools. --- cgminer.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cgminer.c b/cgminer.c index 36b3ddf8..a2ee1eeb 100644 --- a/cgminer.c +++ b/cgminer.c @@ -3040,7 +3040,6 @@ retry: } if (pool->has_gbt) { -#if 0 while (pool->idle) { struct pool *altpool = select_pool(true); @@ -3052,7 +3051,6 @@ retry: goto retry; } } -#endif ret_work = make_work(); gen_gbt_work(pool, ret_work); if (unlikely(!stage_work(ret_work))) { @@ -5011,10 +5009,8 @@ static bool reuse_work(struct work *work, struct pool *pool) } if (pool->has_gbt) { -#if 0 if (pool->idle) return false; -#endif applog(LOG_DEBUG, "Reusing GBT work"); gen_gbt_work(pool, work); return true; From 75d0a45a1081aad1174c97063fc59d3c917a024e Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 5 Nov 2012 23:47:44 +1100 Subject: [PATCH 44/54] Show which pool untracked share messages have come from. --- cgminer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cgminer.c b/cgminer.c index a2ee1eeb..9d8e96a0 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4547,7 +4547,7 @@ static void stratum_share_result(json_t *val, json_t *res_val, json_t *err_val, /* Parses stratum json responses and tries to find the id that the request * matched to and treat it accordingly. */ -static bool parse_stratum_response(char *s) +static bool parse_stratum_response(struct pool *pool, char *s) { json_t *val = NULL, *err_val, *res_val, *id_val; struct stratum_share *sshare; @@ -4588,9 +4588,9 @@ static bool parse_stratum_response(char *s) mutex_unlock(&sshare_lock); if (!sshare) { if (json_is_true(res_val)) - applog(LOG_NOTICE, "Accepted untracked stratum share"); + applog(LOG_NOTICE, "Accepted untracked stratum share from pool %d", pool->pool_no); else - applog(LOG_NOTICE, "Rejected untracked stratum share"); + applog(LOG_NOTICE, "Rejected untracked stratum share from pool %d", pool->pool_no); goto out; } stratum_share_result(val, res_val, err_val, sshare); @@ -4684,7 +4684,7 @@ static void *stratum_thread(void *userdata) continue; } - if (!parse_method(pool, s) && !parse_stratum_response(s)) + if (!parse_method(pool, s) && !parse_stratum_response(pool, s)) applog(LOG_INFO, "Unknown stratum msg: %s", s); free(s); if (pool->swork.clean) { From 418d15deba88fad1057a8c0fa2f20117ec939e80 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 6 Nov 2012 09:43:55 +1100 Subject: [PATCH 45/54] Only retrieve a new block template for GBT pools that are the current pool. --- cgminer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 9d8e96a0..529333e8 100644 --- a/cgminer.c +++ b/cgminer.c @@ -5864,7 +5864,8 @@ static void *watchpool_thread(void __maybe_unused *userdata) * template if more than 30 seconds has elapsed since * the last one to keep the data current and as a test * for when the pool dies. */ - if (!pool->idle && pool->has_gbt && now.tv_sec - pool->tv_template.tv_sec > 60) { + if (!pool->idle && pool->has_gbt && pool == current_pool() && + now.tv_sec - pool->tv_template.tv_sec > 60) { if (!pool_active(pool, true)) pool_died(pool); } From 27ce497a7c37915b683cbae8f9b9ca2dfa2aa1dc Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 6 Nov 2012 09:50:36 +1100 Subject: [PATCH 46/54] Count lost stratum share submits and increase message priority to warning. --- cgminer.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 529333e8..d6990539 100644 --- a/cgminer.c +++ b/cgminer.c @@ -3242,11 +3242,13 @@ static void *submit_work_thread(void *userdata) applog(LOG_WARNING, "Pool %d communication resumed, submitting work", pool->pool_no); applog(LOG_DEBUG, "Successfully submitted, adding to stratum_shares db"); } else { - applog(LOG_INFO, "Failed to submit stratum share"); + applog(LOG_WARNING, "Failed to submit stratum share to pool %d", pool->pool_no); mutex_lock(&sshare_lock); HASH_DEL(stratum_shares, sshare); mutex_unlock(&sshare_lock); free(sshare); + pool->stale_shares++; + total_stale++; if (!pool_tset(pool, &pool->submit_fail)) { total_ro++; From 498882d8293e04d7063d62088a6cd0b58ed2245f Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 6 Nov 2012 10:39:34 +1100 Subject: [PATCH 47/54] Remove resetting of probed variable when detecting GBT. --- cgminer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index d6990539..a0953f11 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4803,7 +4803,7 @@ retry_stratum: } json_decref(val); } - pool->probed = false; + if (pool->has_gbt) applog(LOG_DEBUG, "GBT coinbase append support found, switching to GBT protocol"); else From a47a7886d5e7e3d701b6dd6973625d8235d77644 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 6 Nov 2012 11:39:25 +1100 Subject: [PATCH 48/54] Only retarget stratum shares to new pool diff if diff has dropped. --- cgminer.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index a0953f11..6e64157f 100644 --- a/cgminer.c +++ b/cgminer.c @@ -5320,7 +5320,7 @@ static bool hashtest(struct thr_info *thr, struct work *work) unsigned char hash2[32]; uint32_t *hash2_32 = (uint32_t *)hash2; struct pool *pool = work->pool; - int i, diff; + int i; for (i = 0; i < 80 / 4; i++) swap32[i] = swab32(data32[i]); @@ -5346,11 +5346,15 @@ static bool hashtest(struct thr_info *thr, struct work *work) } if (work->stratum) { + int diff; + mutex_lock(&pool->pool_lock); diff = pool->swork.diff; mutex_unlock(&pool->pool_lock); - if (unlikely(work->sdiff != diff)) { + /* Retarget share only if pool diff has dropped since we + * generated this work */ + if (unlikely(work->sdiff > diff)) { applog(LOG_DEBUG, "Share needs retargetting to match pool"); set_work_target(work, diff); } From a8e1ebb11ca330d9b6bff6a4a3c13afe27643ca5 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 6 Nov 2012 12:01:07 +1100 Subject: [PATCH 49/54] Add endian swap defines for where missing. --- miner.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/miner.h b/miner.h index b8676fd0..827fa4f7 100644 --- a/miner.h +++ b/miner.h @@ -143,11 +143,15 @@ static inline int fsync (int fd) * htobe64 also won't exist */ #ifndef htobe32 # if __BYTE_ORDER == __LITTLE_ENDIAN +# define htole16(x) (x) +# define htole32(x) (x) # define be32toh(x) bswap_32(x) # define be64toh(x) bswap_64(x) # define htobe32(x) bswap_32(x) # define htobe64(x) bswap_64(x) # elif __BYTE_ORDER == __BIG_ENDIAN +# define htole16(x) bswap_16(x) +# define htole32(x) bswap_32(x) # define be32toh(x) (x) # define be64toh(x) (x) # define htobe32(x) (x) From df51751827fa62e6126579c2aef15d6b7c27cdf7 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 6 Nov 2012 11:53:23 +1100 Subject: [PATCH 50/54] Update NEWS. --- NEWS | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/NEWS b/NEWS index 4c270f38..a57b3e0f 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,77 @@ +Version 2.9.0 - November 6, 2012 + +- Only retarget stratum shares to new pool diff if diff has dropped. +- Remove resetting of probed variable when detecting GBT. +- Count lost stratum share submits and increase message priority to warning. +- Only retrieve a new block template for GBT pools that are the current pool. +- Show which pool untracked share messages have come from. +- Add management for dead GBT pools. +- Count lost shares with stratum as submit stale lost. +- Discard record of stratum shares sent and report lost shares on disconnection +since they will never be reported back. +- Swab, don't just swap the bytes in the GBT target. +- Change status window message for GBT connected pools versus LP. +- Generate a gbt work item from longpoll when required to set new block and +message appropriately. +- Use existing pool submit_old bool from gbt data. +- Retrieve a new block template if more than 30 seconds has elapsed since the +last one to keep the data current and test the pool is still alive. +- Update GBT longpollid every time we request a new longpoll. +- Manage appropriate response codes for share submission with GBT. +- Allow the longpoll thread to start with GBT and only set the longpollid once. +- Correct last few components of GBT block generation courtesy of Luke-jr. +- Use correct length for offsetting extra nonce and remaining data. +- Flip all 80 bytes in the flip function which was wrongly named flip256 for its +purpose. +- Calculate midstate for gbt work and remove now unused variable. +- Use a standard function for flipping bytes. +- Insert the extra nonce and remaining data in the correct position in the +coinbase. +- Remove txn size debugging and enlarge gbt block string to prevent overflow. +- Remove varint display debugging. +- Build varint correctly for share submission and sleep 5 seconds before +retrying submit. +- Make gbt_coinbase large enough for submissions, swap bytes correctly to make a +header from GBT and encode the number of transactions in share submission. +- Store the fixed size entries as static variables in GBT in binary form, +byteswapping as is required. +- 32 bit hex encoded variables should be in LE with GBT. +- Target and prevblockhash need to be reversed from GBT variables. +- Construct block for submission when using GBT. +- Use same string for debug as for submission and make string larger to cope +with future GBT messages. +- Skip trying to decipher LP url if we have GBT support. +- Store all the transaction hashes in pool->txn_hashes instead of separating +txn0 and correct generation of merkle root, fixing memory overwrites. +- Hook into various places to generate GBT work where appropriate. +- Create extra work fields when generating GBT work. +- Generate header from correct hashing generation of the merkle root for GBT. +- Generate the merkle root for gbt work generation. +- Create a store of the transactions with GBT in the minimum size form required +to generate work items with a varied coinbase. +- Create a function that generates a GBT coinbase from the existing pool +variables. +- Extract and store the various variables GBT uses when decoding gbt work. +- Check for invalid json result in work_decode. +- Decode work in separate functions for getwork vs gbt. +- Check for the coinbase/append mutable in GBT support to decide whether to use +it or not. +- Add a gbt mutex within the pool struct for protecting the gbt values. +- Convert work decode function to prepare for decoding block templates. +- Check for GBT support on first probing the pool and convert to using the GBT +request as the rpc request for that pool. +- Make the rpc request used with getwork a pool variable to allow it to be +converted to/from gbt requests. +- Changes to build prototypes to support building on FreeBSD 9.1-RC2 amd64 +- Free old stratum_work data before replacing it +- There is no need for addrinfo any more. +- server and client sockaddr_in are no longer used in struct pool. +- Merge pull request #322 from luke-jr/bugfix_stratum_tmpwork +- Set sshare id and swork_id within the sshare mutex to avoid multiple share +submits with the same id. +- Initialize temporary stratum work + + Version 2.8.7 - October 29, 2012 - Fail on select() failing in stratum thread without needing to attempt From d6b9442fcfec06001d8cf77f70e8960c967ec534 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 6 Nov 2012 11:54:09 +1100 Subject: [PATCH 51/54] Bump version to 2.9.0 --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 8e201c9c..9a71a5a2 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## m4_define([v_maj], [2]) -m4_define([v_min], [8]) -m4_define([v_mic], [7]) +m4_define([v_min], [9]) +m4_define([v_mic], [0]) ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## m4_define([v_ver], [v_maj.v_min.v_mic]) m4_define([lt_rev], m4_eval(v_maj + v_min)) From be82cc7fbaaa265a252067360021094f46b2696d Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 6 Nov 2012 14:01:32 +1100 Subject: [PATCH 52/54] Reset work flags to prevent GBT shares from being submitted as stratum ones after switching. --- cgminer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cgminer.c b/cgminer.c index 6e64157f..8035de41 100644 --- a/cgminer.c +++ b/cgminer.c @@ -5206,6 +5206,8 @@ static void get_work(struct work *work, struct thr_info *thr, const int thr_id) goto out; } + /* Reset these flags in case we switch pools with these work structs */ + work->stratum = work->gbt = false; retry: pool = current_pool(); From b57edb45527d310bb1d5ae3c80ec4d57b24c382d Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 6 Nov 2012 14:51:32 +1100 Subject: [PATCH 53/54] Bump version and news to 2.9.1. --- NEWS | 7 +++++++ configure.ac | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index a57b3e0f..285e7990 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,12 @@ +Version 2.9.1 - November 6, 2012 + +- Reset work flags to prevent GBT shares from being submitted as stratum ones +after switching. + + Version 2.9.0 - November 6, 2012 +- Add endian swap defines for where missing. - Only retarget stratum shares to new pool diff if diff has dropped. - Remove resetting of probed variable when detecting GBT. - Count lost stratum share submits and increase message priority to warning. diff --git a/configure.ac b/configure.ac index 9a71a5a2..de6dc0ab 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## m4_define([v_maj], [2]) m4_define([v_min], [9]) -m4_define([v_mic], [0]) +m4_define([v_mic], [1]) ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## m4_define([v_ver], [v_maj.v_min.v_mic]) m4_define([lt_rev], m4_eval(v_maj + v_min)) From dd671baaa100bd29affa83f8fb08575dec6f3914 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 6 Nov 2012 17:42:49 +1100 Subject: [PATCH 54/54] Get a fresh block template with GBT pools on switching to them. --- cgminer.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 8035de41..af2936fa 100644 --- a/cgminer.c +++ b/cgminer.c @@ -3319,6 +3319,8 @@ static struct pool *priority_pool(int choice) return ret; } +static bool pool_active(struct pool *pool, bool pinging); + void switch_pools(struct pool *selected) { struct pool *pool, *last_pool; @@ -3387,8 +3389,13 @@ void switch_pools(struct pool *selected) if (opt_fail_only) pool_tset(pool, &pool->lagging); - if (pool != last_pool) + if (pool != last_pool) { applog(LOG_WARNING, "Switching to %s", pool->rpc_url); + /* Get a fresh block template since we may not have an up to + * date one */ + if (pool->has_gbt) + pool_active(pool, true); + } mutex_lock(&lp_lock); pthread_cond_broadcast(&lp_cond);