From b3cdd8029ad8ce4f359668ee3634255bd5b83bbb Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 24 Sep 2012 16:27:47 +1000 Subject: [PATCH 001/160] Put all socket definitions in util.h to allow reusing by added socket functions to be used in util.c. --- Makefile.am | 2 +- api.c | 103 +-------------------------------------------------- util.h | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+), 102 deletions(-) create mode 100644 util.h diff --git a/Makefile.am b/Makefile.am index e37abf46..f4ed5e1d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -32,7 +32,7 @@ cgminer_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib @OPENCL_FLAGS@ cgminer_SOURCES := cgminer.c cgminer_SOURCES += elist.h miner.h compat.h bench_block.h \ - util.c uthash.h logging.h \ + util.c util.h uthash.h logging.h \ sha2.c sha2.h api.c cgminer_SOURCES += logging.c diff --git a/api.c b/api.c index 8ebf94da..f9e53725 100644 --- a/api.c +++ b/api.c @@ -25,6 +25,7 @@ #include "compat.h" #include "miner.h" +#include "util.h" #include "driver-cpu.h" /* for algo_names[], TODO: re-factor dependency */ #if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX) || defined(USE_MODMINER) @@ -36,109 +37,9 @@ #include #include #include - - #define SOCKETTYPE int - #define SOCKETFAIL(a) ((a) < 0) - #define INVSOCK -1 - #define INVINETADDR -1 - #define CLOSESOCKET close - - #define SOCKERRMSG strerror(errno) -#endif - -#ifdef WIN32 +#elif defined WIN32 #include #include - - #define SOCKETTYPE SOCKET - #define SOCKETFAIL(a) ((a) == SOCKET_ERROR) - #define INVSOCK INVALID_SOCKET - #define INVINETADDR INADDR_NONE - #define CLOSESOCKET closesocket - - static char WSAbuf[1024]; - - struct WSAERRORS { - int id; - char *code; - } WSAErrors[] = { - { 0, "No error" }, - { WSAEINTR, "Interrupted system call" }, - { WSAEBADF, "Bad file number" }, - { WSAEACCES, "Permission denied" }, - { WSAEFAULT, "Bad address" }, - { WSAEINVAL, "Invalid argument" }, - { WSAEMFILE, "Too many open sockets" }, - { WSAEWOULDBLOCK, "Operation would block" }, - { WSAEINPROGRESS, "Operation now in progress" }, - { WSAEALREADY, "Operation already in progress" }, - { WSAENOTSOCK, "Socket operation on non-socket" }, - { WSAEDESTADDRREQ, "Destination address required" }, - { WSAEMSGSIZE, "Message too long" }, - { WSAEPROTOTYPE, "Protocol wrong type for socket" }, - { WSAENOPROTOOPT, "Bad protocol option" }, - { WSAEPROTONOSUPPORT, "Protocol not supported" }, - { WSAESOCKTNOSUPPORT, "Socket type not supported" }, - { WSAEOPNOTSUPP, "Operation not supported on socket" }, - { WSAEPFNOSUPPORT, "Protocol family not supported" }, - { WSAEAFNOSUPPORT, "Address family not supported" }, - { WSAEADDRINUSE, "Address already in use" }, - { WSAEADDRNOTAVAIL, "Can't assign requested address" }, - { WSAENETDOWN, "Network is down" }, - { WSAENETUNREACH, "Network is unreachable" }, - { WSAENETRESET, "Net connection reset" }, - { WSAECONNABORTED, "Software caused connection abort" }, - { WSAECONNRESET, "Connection reset by peer" }, - { WSAENOBUFS, "No buffer space available" }, - { WSAEISCONN, "Socket is already connected" }, - { WSAENOTCONN, "Socket is not connected" }, - { WSAESHUTDOWN, "Can't send after socket shutdown" }, - { WSAETOOMANYREFS, "Too many references, can't splice" }, - { WSAETIMEDOUT, "Connection timed out" }, - { WSAECONNREFUSED, "Connection refused" }, - { WSAELOOP, "Too many levels of symbolic links" }, - { WSAENAMETOOLONG, "File name too long" }, - { WSAEHOSTDOWN, "Host is down" }, - { WSAEHOSTUNREACH, "No route to host" }, - { WSAENOTEMPTY, "Directory not empty" }, - { WSAEPROCLIM, "Too many processes" }, - { WSAEUSERS, "Too many users" }, - { WSAEDQUOT, "Disc quota exceeded" }, - { WSAESTALE, "Stale NFS file handle" }, - { WSAEREMOTE, "Too many levels of remote in path" }, - { WSASYSNOTREADY, "Network system is unavailable" }, - { WSAVERNOTSUPPORTED, "Winsock version out of range" }, - { WSANOTINITIALISED, "WSAStartup not yet called" }, - { WSAEDISCON, "Graceful shutdown in progress" }, - { WSAHOST_NOT_FOUND, "Host not found" }, - { WSANO_DATA, "No host data of that type was found" }, - { -1, "Unknown error code" } - }; - - static char *WSAErrorMsg() - { - int i; - int id = WSAGetLastError(); - - /* Assume none of them are actually -1 */ - for (i = 0; WSAErrors[i].id != -1; i++) - if (WSAErrors[i].id == id) - break; - - sprintf(WSAbuf, "Socket Error: (%d) %s", id, WSAErrors[i].code); - - return &(WSAbuf[0]); - } - - #define SOCKERRMSG WSAErrorMsg() - - #ifndef SHUT_RDWR - #define SHUT_RDWR SD_BOTH - #endif - - #ifndef in_addr_t - #define in_addr_t uint32_t - #endif #endif // Big enough for largest API request diff --git a/util.h b/util.h new file mode 100644 index 00000000..6f125be1 --- /dev/null +++ b/util.h @@ -0,0 +1,104 @@ +#ifndef __UTIL_H__ +#define __UTIL_H__ + +#if defined(unix) || defined(__APPLE__) + #define SOCKETTYPE int + #define SOCKETFAIL(a) ((a) < 0) + #define INVSOCK -1 + #define INVINETADDR -1 + #define CLOSESOCKET close + + #define SOCKERRMSG strerror(errno) +#elif defined WIN32 + #define SOCKETTYPE SOCKET + #define SOCKETFAIL(a) ((a) == SOCKET_ERROR) + #define INVSOCK INVALID_SOCKET + #define INVINETADDR INADDR_NONE + #define CLOSESOCKET closesocket + + static char WSAbuf[1024]; + + struct WSAERRORS { + int id; + char *code; + } WSAErrors[] = { + { 0, "No error" }, + { WSAEINTR, "Interrupted system call" }, + { WSAEBADF, "Bad file number" }, + { WSAEACCES, "Permission denied" }, + { WSAEFAULT, "Bad address" }, + { WSAEINVAL, "Invalid argument" }, + { WSAEMFILE, "Too many open sockets" }, + { WSAEWOULDBLOCK, "Operation would block" }, + { WSAEINPROGRESS, "Operation now in progress" }, + { WSAEALREADY, "Operation already in progress" }, + { WSAENOTSOCK, "Socket operation on non-socket" }, + { WSAEDESTADDRREQ, "Destination address required" }, + { WSAEMSGSIZE, "Message too long" }, + { WSAEPROTOTYPE, "Protocol wrong type for socket" }, + { WSAENOPROTOOPT, "Bad protocol option" }, + { WSAEPROTONOSUPPORT, "Protocol not supported" }, + { WSAESOCKTNOSUPPORT, "Socket type not supported" }, + { WSAEOPNOTSUPP, "Operation not supported on socket" }, + { WSAEPFNOSUPPORT, "Protocol family not supported" }, + { WSAEAFNOSUPPORT, "Address family not supported" }, + { WSAEADDRINUSE, "Address already in use" }, + { WSAEADDRNOTAVAIL, "Can't assign requested address" }, + { WSAENETDOWN, "Network is down" }, + { WSAENETUNREACH, "Network is unreachable" }, + { WSAENETRESET, "Net connection reset" }, + { WSAECONNABORTED, "Software caused connection abort" }, + { WSAECONNRESET, "Connection reset by peer" }, + { WSAENOBUFS, "No buffer space available" }, + { WSAEISCONN, "Socket is already connected" }, + { WSAENOTCONN, "Socket is not connected" }, + { WSAESHUTDOWN, "Can't send after socket shutdown" }, + { WSAETOOMANYREFS, "Too many references, can't splice" }, + { WSAETIMEDOUT, "Connection timed out" }, + { WSAECONNREFUSED, "Connection refused" }, + { WSAELOOP, "Too many levels of symbolic links" }, + { WSAENAMETOOLONG, "File name too long" }, + { WSAEHOSTDOWN, "Host is down" }, + { WSAEHOSTUNREACH, "No route to host" }, + { WSAENOTEMPTY, "Directory not empty" }, + { WSAEPROCLIM, "Too many processes" }, + { WSAEUSERS, "Too many users" }, + { WSAEDQUOT, "Disc quota exceeded" }, + { WSAESTALE, "Stale NFS file handle" }, + { WSAEREMOTE, "Too many levels of remote in path" }, + { WSASYSNOTREADY, "Network system is unavailable" }, + { WSAVERNOTSUPPORTED, "Winsock version out of range" }, + { WSANOTINITIALISED, "WSAStartup not yet called" }, + { WSAEDISCON, "Graceful shutdown in progress" }, + { WSAHOST_NOT_FOUND, "Host not found" }, + { WSANO_DATA, "No host data of that type was found" }, + { -1, "Unknown error code" } + }; + + static char *WSAErrorMsg() + { + int i; + int id = WSAGetLastError(); + + /* Assume none of them are actually -1 */ + for (i = 0; WSAErrors[i].id != -1; i++) + if (WSAErrors[i].id == id) + break; + + sprintf(WSAbuf, "Socket Error: (%d) %s", id, WSAErrors[i].code); + + return &(WSAbuf[0]); + } + + #define SOCKERRMSG WSAErrorMsg() + + #ifndef SHUT_RDWR + #define SHUT_RDWR SD_BOTH + #endif + + #ifndef in_addr_t + #define in_addr_t uint32_t + #endif +#endif + +#endif /* __UTIL_H__ */ From 144a016097321f833af219439f75810b413b22c1 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 24 Sep 2012 16:50:04 +1000 Subject: [PATCH 002/160] Add data structures to pool struct for socket communications. --- api.c | 10 ---------- miner.h | 4 ++++ util.h | 8 ++++++++ 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/api.c b/api.c index f9e53725..361375a2 100644 --- a/api.c +++ b/api.c @@ -32,16 +32,6 @@ #define HAVE_AN_FPGA 1 #endif -#if defined(unix) || defined(__APPLE__) - #include - #include - #include - #include -#elif defined WIN32 - #include - #include -#endif - // Big enough for largest API request // though a PC with 100s of PGAs/CPUs may exceed the size ... // Current code assumes it can socket send this size also diff --git a/miner.h b/miner.h index 169c9ee1..175a3fc9 100644 --- a/miner.h +++ b/miner.h @@ -12,6 +12,7 @@ #include "elist.h" #include "uthash.h" #include "logging.h" +#include "util.h" #ifdef HAVE_OPENCL #ifdef __APPLE_CC__ @@ -810,6 +811,9 @@ struct pool { struct cgminer_stats cgminer_stats; struct cgminer_pool_stats cgminer_pool_stats; + + SOCKETTYPE sock; + struct sockaddr_in server, client; }; #define GETWORK_MODE_TESTPOOL 'T' diff --git a/util.h b/util.h index 6f125be1..3dcc9485 100644 --- a/util.h +++ b/util.h @@ -2,6 +2,11 @@ #define __UTIL_H__ #if defined(unix) || defined(__APPLE__) + #include + #include + #include + #include + #define SOCKETTYPE int #define SOCKETFAIL(a) ((a) < 0) #define INVSOCK -1 @@ -10,6 +15,9 @@ #define SOCKERRMSG strerror(errno) #elif defined WIN32 + #include + #include + #define SOCKETTYPE SOCKET #define SOCKETFAIL(a) ((a) == SOCKET_ERROR) #define INVSOCK INVALID_SOCKET From 5e7e150b12ed82c41eac4dc77f867ab38168267d Mon Sep 17 00:00:00 2001 From: Kano Date: Mon, 24 Sep 2012 23:34:10 +1000 Subject: [PATCH 003/160] hashmeter fix stats kh/s on 32bit windows --- cgminer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index 10c92207..6676c8ce 100644 --- a/cgminer.c +++ b/cgminer.c @@ -3821,7 +3821,7 @@ static inline void thread_reportout(struct thr_info *thr) } static void hashmeter(int thr_id, struct timeval *diff, - unsigned long long hashes_done) + uint64_t hashes_done) { struct timeval temp_tv_end, total_diff; double secs; @@ -3849,7 +3849,7 @@ static void hashmeter(int thr_id, struct timeval *diff, double thread_rolling = 0.0; int i; - applog(LOG_DEBUG, "[thread %d: %llu hashes, %.1f khash/sec]", + applog(LOG_DEBUG, "[thread %d: %"PRIu64" hashes, %.1f khash/sec]", thr_id, hashes_done, hashes_done / 1000 / secs); /* Rolling average for each thread and each device */ From ee3b7865e24d0eb63e40624514cb91432e58e48a Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 25 Sep 2012 05:46:07 +1000 Subject: [PATCH 004/160] Prepare for getaddrinfo call. --- cgminer.c | 2 ++ util.c | 32 ++++++++++++++++++++++++++++++++ util.h | 2 ++ 3 files changed, 36 insertions(+) diff --git a/cgminer.c b/cgminer.c index 10c92207..67197c3c 100644 --- a/cgminer.c +++ b/cgminer.c @@ -554,6 +554,8 @@ static char *set_url(char *arg) arg = get_proxy(arg, pool); + extract_sockaddr(pool, arg); + opt_set_charp(arg, &pool->rpc_url); if (strncmp(arg, "http://", 7) && strncmp(arg, "https://", 8)) { diff --git a/util.c b/util.c index 3a0dbc18..ef5232b7 100644 --- a/util.c +++ b/util.c @@ -30,6 +30,7 @@ # include # include #endif +#include #include "miner.h" #include "elist.h" @@ -794,3 +795,34 @@ double tdiff(struct timeval *end, struct timeval *start) { return end->tv_sec - start->tv_sec + (end->tv_usec - start->tv_usec) / 1000000.0; } + +void extract_sockaddr(struct pool *pool, char *url) +{ + char *url_begin, *url_end, *url_address; + char *port_start, port80[3] = "80"; + struct addrinfo hints, *res; + size_t url_len, port_len; + + url_begin = strstr(url, "//"); + if (!url_begin) + url_begin = url; + else + url_begin += 2; + url_end = strstr(url_begin, ":"); + if (url_end) { + url_len = url_end - 1 - url_begin; + port_len = strlen(url_begin) - url_len - 1; + if (port_len <= 1) + return; + port_start = url_end + 1; + } else { + url_len = strlen(url_begin); + port_start = port80; + } + if (url_len <= 1) + return; + + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; +} diff --git a/util.h b/util.h index 3dcc9485..b8c062b2 100644 --- a/util.h +++ b/util.h @@ -108,5 +108,7 @@ #define in_addr_t uint32_t #endif #endif +struct pool; +void extract_sockaddr(struct pool *pool, char *url); #endif /* __UTIL_H__ */ From 036c3382111aaaf9850935ac14d919ee550e589d Mon Sep 17 00:00:00 2001 From: Kano Date: Tue, 25 Sep 2012 11:04:06 +1000 Subject: [PATCH 005/160] API-README update cgminer verison number --- API-README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/API-README b/API-README index a1c54c55..7e5fac88 100644 --- a/API-README +++ b/API-README @@ -383,7 +383,7 @@ miner.php - an example web page to access the API Feature Changelog for external applications using the API: -API V1.19 +API V1.19 (cgminer v2.7.6) Added API commands: 'debug' From 58873c1dfa5a44476b56323412d53c77f6648794 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 25 Sep 2012 20:23:59 +1000 Subject: [PATCH 006/160] Get detailed addressinfo from the parsed URL for future raw socket usage when possible. IPV4 only for now. --- cgminer.c | 3 ++- miner.h | 2 +- util.c | 41 ++++++++++++++++++++++++++++++----------- util.h | 2 +- 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/cgminer.c b/cgminer.c index 67197c3c..000782c2 100644 --- a/cgminer.c +++ b/cgminer.c @@ -554,7 +554,8 @@ static char *set_url(char *arg) arg = get_proxy(arg, pool); - extract_sockaddr(pool, arg); + if (!extract_sockaddr(pool, arg)) + return "Failed to extract address from parsed url"; opt_set_charp(arg, &pool->rpc_url); if (strncmp(arg, "http://", 7) && diff --git a/miner.h b/miner.h index 175a3fc9..572444ba 100644 --- a/miner.h +++ b/miner.h @@ -813,7 +813,7 @@ struct pool { struct cgminer_pool_stats cgminer_pool_stats; SOCKETTYPE sock; - struct sockaddr_in server, client; + struct sockaddr_in *server, client; }; #define GETWORK_MODE_TESTPOOL 'T' diff --git a/util.c b/util.c index ef5232b7..6ac80641 100644 --- a/util.c +++ b/util.c @@ -796,12 +796,12 @@ double tdiff(struct timeval *end, struct timeval *start) return end->tv_sec - start->tv_sec + (end->tv_usec - start->tv_usec) / 1000000.0; } -void extract_sockaddr(struct pool *pool, char *url) +bool extract_sockaddr(struct pool *pool, char *url) { - char *url_begin, *url_end, *url_address; - char *port_start, port80[3] = "80"; + char *url_begin, *url_end, *port_start; + char *url_address, *port; struct addrinfo hints, *res; - size_t url_len, port_len; + size_t url_len, port_len = 0; url_begin = strstr(url, "//"); if (!url_begin) @@ -810,19 +810,38 @@ void extract_sockaddr(struct pool *pool, char *url) url_begin += 2; url_end = strstr(url_begin, ":"); if (url_end) { - url_len = url_end - 1 - url_begin; + url_len = url_end - url_begin; port_len = strlen(url_begin) - url_len - 1; - if (port_len <= 1) - return; + if (port_len < 1) + return false; port_start = url_end + 1; - } else { + } else url_len = strlen(url_begin); - port_start = port80; + + if (url_len < 1) + return false; + + url_address = alloca(url_len + 1); + sprintf(url_address, "%.*s", url_len, url_begin); + + if (port_len) { + port = alloca(port_len + 1); + sprintf(port, "%.*s", port_len, port_start); + } else { + port = alloca(4); + strcpy(port, "80"); } - if (url_len <= 1) - return; + memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; + + if (getaddrinfo(url_address, port, &hints, &res)) { + applog(LOG_DEBUG, "Failed to extract sock addr"); + return false; + } + + pool->server = (struct sockaddr_in *)res->ai_addr; + return true; } diff --git a/util.h b/util.h index b8c062b2..c99ecfd2 100644 --- a/util.h +++ b/util.h @@ -109,6 +109,6 @@ #endif #endif struct pool; -void extract_sockaddr(struct pool *pool, char *url); +bool extract_sockaddr(struct pool *pool, char *url); #endif /* __UTIL_H__ */ From a1b17229b8059ef89ae6a8d64b4fbae528a9ead2 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 26 Sep 2012 15:23:01 +1000 Subject: [PATCH 007/160] Initiate stratum and grab first json result. --- cgminer.c | 2 ++ util.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ util.h | 1 + 3 files changed, 96 insertions(+) diff --git a/cgminer.c b/cgminer.c index 000782c2..63412c14 100644 --- a/cgminer.c +++ b/cgminer.c @@ -557,6 +557,8 @@ static char *set_url(char *arg) if (!extract_sockaddr(pool, arg)) return "Failed to extract address from parsed url"; + initiate_stratum(pool); + opt_set_charp(arg, &pool->rpc_url); if (strncmp(arg, "http://", 7) && strncmp(arg, "https://", 8)) { diff --git a/util.c b/util.c index 6ac80641..79c7e8fd 100644 --- a/util.c +++ b/util.c @@ -845,3 +845,96 @@ bool extract_sockaddr(struct pool *pool, char *url) pool->server = (struct sockaddr_in *)res->ai_addr; return true; } + +static bool sock_send(int sock, char *s, ssize_t len) +{ + size_t sent = 0; + + while (len > 0 ) { + sent = send(sock, s + sent, len, 0); + if (sent < 1) + return false; + len -= sent; + } + fsync(sock); + + return true; +} + +#define RECVSIZE 8192 + +bool initiate_stratum(struct pool *pool) +{ + json_t *val, *res_val, *err_val; + struct timeval timeout; + char *s, *ret = NULL; + json_error_t err; + ssize_t len; + fd_set rd; + + s = alloca(RECVSIZE); + sprintf(s, "{\"id\": 0, \"method\": \"mining.subscribe\", \"params\": []}\n"); + + pool->sock = socket(AF_INET, SOCK_STREAM, 0); + if (pool->sock == INVSOCK) + quit(1, "Failed to create pool socket in initiate_stratum"); + if (SOCKETFAIL(connect(pool->sock, (struct sockaddr *)pool->server, sizeof(struct sockaddr)))) { + applog(LOG_DEBUG, "Failed to connect socket to pool"); + return false; + } + + if (!sock_send(pool->sock, s, strlen(s))) { + applog(LOG_DEBUG, "Failed to send s in initiate_stratum"); + return false; + } + + /* Use select to timeout instead of waiting forever for a response */ + FD_ZERO(&rd); + FD_SET(pool->sock, &rd); + timeout.tv_sec = 60; + if (select(pool->sock + 1, &rd, NULL, NULL, &timeout) < 1) { + applog(LOG_DEBUG, "Timed out waiting for response in initiate_stratum"); + return false; + } + + if (recv(pool->sock, s, RECVSIZE, MSG_PEEK | MSG_DONTWAIT) < 1) { + applog(LOG_DEBUG, "Failed to recv sock in initiate_stratum"); + return false; + } + + ret = strtok(s, "\n"); + if (!ret) { + applog(LOG_DEBUG, "Failed to parse a \\n terminated string in initiate_stratum"); + return false; + } + + len = strlen(ret); + read(pool->sock, s, len); + + val = JSON_LOADS(s, &err); + if (!val) { + applog(LOG_DEBUG, "JSON decode failed(%d): %s", err.line, err.text); + return false; + } + + 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))) { + char *ss; + + if (err_val) + ss = json_dumps(err_val, JSON_INDENT(3)); + else + ss = strdup("(unknown reason)"); + + applog(LOG_INFO, "JSON-RPC call failed: %s", ss); + + free(ss); + + return false; + } + + return true; +} diff --git a/util.h b/util.h index c99ecfd2..72304fec 100644 --- a/util.h +++ b/util.h @@ -110,5 +110,6 @@ #endif struct pool; bool extract_sockaddr(struct pool *pool, char *url); +bool initiate_stratum(struct pool *pool); #endif /* __UTIL_H__ */ From c0de671c4fbddd6430fca61e2477bfa256e51c1d Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 26 Sep 2012 15:40:26 +1000 Subject: [PATCH 008/160] Use existing socket macros and close the socket on failure in init stratum. --- util.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/util.c b/util.c index 79c7e8fd..d675d26c 100644 --- a/util.c +++ b/util.c @@ -852,7 +852,7 @@ static bool sock_send(int sock, char *s, ssize_t len) while (len > 0 ) { sent = send(sock, s + sent, len, 0); - if (sent < 1) + if (SOCKETFAIL(sent)) return false; len -= sent; } @@ -867,8 +867,9 @@ bool initiate_stratum(struct pool *pool) { json_t *val, *res_val, *err_val; struct timeval timeout; - char *s, *ret = NULL; + char *s, *sret = NULL; json_error_t err; + bool ret = false; ssize_t len; fd_set rd; @@ -880,12 +881,12 @@ bool initiate_stratum(struct pool *pool) quit(1, "Failed to create pool socket in initiate_stratum"); if (SOCKETFAIL(connect(pool->sock, (struct sockaddr *)pool->server, sizeof(struct sockaddr)))) { applog(LOG_DEBUG, "Failed to connect socket to pool"); - return false; + goto out; } if (!sock_send(pool->sock, s, strlen(s))) { applog(LOG_DEBUG, "Failed to send s in initiate_stratum"); - return false; + goto out; } /* Use select to timeout instead of waiting forever for a response */ @@ -894,27 +895,28 @@ bool initiate_stratum(struct pool *pool) timeout.tv_sec = 60; if (select(pool->sock + 1, &rd, NULL, NULL, &timeout) < 1) { applog(LOG_DEBUG, "Timed out waiting for response in initiate_stratum"); - return false; + goto out; } - if (recv(pool->sock, s, RECVSIZE, MSG_PEEK | MSG_DONTWAIT) < 1) { + if (SOCKETFAIL(recv(pool->sock, s, RECVSIZE, MSG_PEEK | MSG_DONTWAIT))) { applog(LOG_DEBUG, "Failed to recv sock in initiate_stratum"); - return false; + goto out; } - ret = strtok(s, "\n"); - if (!ret) { + sret = strtok(s, "\n"); + if (!sret) { applog(LOG_DEBUG, "Failed to parse a \\n terminated string in initiate_stratum"); - return false; + goto out; } - len = strlen(ret); + /* We know how much data is in the buffer so this read should not fail */ + len = strlen(sret); read(pool->sock, s, len); val = JSON_LOADS(s, &err); if (!val) { applog(LOG_DEBUG, "JSON decode failed(%d): %s", err.line, err.text); - return false; + goto out; } res_val = json_object_get(val, "result"); @@ -933,8 +935,13 @@ bool initiate_stratum(struct pool *pool) free(ss); - return false; + goto out; } - return true; + ret = true; +out: + if (!ret) + CLOSESOCKET(pool->sock); + + return ret; } From e3f1b02e9a4b86da2a5d25dc6ed05f5fbd7fb6f4 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 26 Sep 2012 16:49:51 +1000 Subject: [PATCH 009/160] Extract and store various parameters on stratum init confirming successful mining notify. --- miner.h | 4 ++++ util.c | 39 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/miner.h b/miner.h index 572444ba..f1a284e7 100644 --- a/miner.h +++ b/miner.h @@ -812,8 +812,12 @@ struct pool { struct cgminer_stats cgminer_stats; struct cgminer_pool_stats cgminer_pool_stats; + /* Stratum variables */ SOCKETTYPE sock; struct sockaddr_in *server, client; + char *subscription; + char *nonce1; + int nonce2; }; #define GETWORK_MODE_TESTPOOL 'T' diff --git a/util.c b/util.c index d675d26c..02c4c28c 100644 --- a/util.c +++ b/util.c @@ -865,9 +865,9 @@ static bool sock_send(int sock, char *s, ssize_t len) bool initiate_stratum(struct pool *pool) { - json_t *val, *res_val, *err_val; + json_t *val, *res_val, *err_val, *notify_val; + char *s, *buf, *sret = NULL; struct timeval timeout; - char *s, *sret = NULL; json_error_t err; bool ret = false; ssize_t len; @@ -938,10 +938,43 @@ bool initiate_stratum(struct pool *pool) goto out; } + notify_val = json_array_get(res_val, 0); + if (!notify_val || json_is_null(notify_val)) { + applog(LOG_WARNING, "Failed to parse notify_val in initiate_stratum"); + goto out; + } + + buf = (char *)json_string_value(json_array_get(notify_val, 0)); + if (!buf || strcasecmp(buf, "mining.notify")) { + applog(LOG_WARNING, "Failed to get mining notify in initiate_stratum"); + goto out; + } + pool->subscription = (char *)json_string_value(json_array_get(notify_val, 1)); + if (!pool->subscription) { + applog(LOG_WARNING, "Failed to get a subscription in initiate_stratum"); + goto out; + } + + pool->nonce1 = (char *)json_string_value(json_array_get(res_val, 1)); + if (!pool->nonce1) { + applog(LOG_WARNING, "Failed to get nonce1 in initiate_stratum"); + goto out; + } + pool->nonce2 = json_integer_value(json_array_get(res_val, 2)); + if (!pool->nonce2) { + applog(LOG_WARNING, "Failed to get nonce2 in initiate_stratum"); + goto out; + } + ret = true; out: - if (!ret) + if (!ret) { CLOSESOCKET(pool->sock); + if (val) + json_decref(val); + } else if (opt_protocol) + applog(LOG_DEBUG, "Pool %d confirmed mining.notify with subscription %s extranonce1 %s extranonce2 %d", + pool->pool_no, pool->subscription, pool->nonce1, pool->nonce2); return ret; } From 8fd149eec9832a9266021447b1a545871d96c3f6 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 26 Sep 2012 16:51:08 +1000 Subject: [PATCH 010/160] Fix warnings. --- util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util.c b/util.c index 02c4c28c..c5d0f765 100644 --- a/util.c +++ b/util.c @@ -801,7 +801,7 @@ bool extract_sockaddr(struct pool *pool, char *url) char *url_begin, *url_end, *port_start; char *url_address, *port; struct addrinfo hints, *res; - size_t url_len, port_len = 0; + int url_len, port_len = 0; url_begin = strstr(url, "//"); if (!url_begin) @@ -848,7 +848,7 @@ bool extract_sockaddr(struct pool *pool, char *url) static bool sock_send(int sock, char *s, ssize_t len) { - size_t sent = 0; + ssize_t sent = 0; while (len > 0 ) { sent = send(sock, s + sent, len, 0); From f6f43500c075bce5c897664e53bd5dac812319bd Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 27 Sep 2012 09:06:56 +1000 Subject: [PATCH 011/160] Detect stratum in common place when adding urls, and use a bool to tell us when it's active. --- api.c | 5 ++++- cgminer.c | 57 ++++++++++++++++++++++++++++++++++++------------------- miner.h | 6 +++++- util.c | 10 +++++++--- 4 files changed, 53 insertions(+), 25 deletions(-) diff --git a/api.c b/api.c index 361375a2..f8171e0a 100644 --- a/api.c +++ b/api.c @@ -2101,6 +2101,7 @@ exitsama: static void addpool(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { char *url, *user, *pass; + struct pool *pool; char *ptr; if (param == NULL || *param == '\0') { @@ -2117,7 +2118,9 @@ static void addpool(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __may return; } - add_pool_details(true, url, user, pass); + pool = add_pool(); + detect_stratum(pool, url); + add_pool_details(pool, true, url, user, pass); ptr = escape_string(url, isjson); strcpy(io_buffer, message(MSG_ADDPOOL, 0, ptr, isjson)); diff --git a/cgminer.c b/cgminer.c index 63412c14..85574acf 100644 --- a/cgminer.c +++ b/cgminer.c @@ -403,7 +403,7 @@ static void sharelog(const char*disposition, const struct work*work) } /* Return value is ignored if not called from add_pool_details */ -static struct pool *add_pool(void) +struct pool *add_pool(void) { struct pool *pool; @@ -543,6 +543,25 @@ static char *set_rr(enum pool_strategy *strategy) return NULL; } +/* Detect that url is for a stratum protocol either via the presence of + * stratum+tcp or by detecting a stratum server response */ +bool detect_stratum(struct pool *pool, char *url) +{ + bool stratum; + + if (!extract_sockaddr(pool, url)) + return false; + + stratum = initiate_stratum(pool); + + if (!strncasecmp(url, "stratum+tcp://", 14) || stratum) { + pool->has_stratum = true; + return true; + } + + return false; +} + static char *set_url(char *arg) { struct pool *pool; @@ -554,10 +573,8 @@ static char *set_url(char *arg) arg = get_proxy(arg, pool); - if (!extract_sockaddr(pool, arg)) - return "Failed to extract address from parsed url"; - - initiate_stratum(pool); + if (detect_stratum(pool, arg)) + return NULL; opt_set_charp(arg, &pool->rpc_url); if (strncmp(arg, "http://", 7) && @@ -5160,12 +5177,8 @@ char *curses_input(const char *query) } #endif -void add_pool_details(bool live, char *url, char *user, char *pass) +void add_pool_details(struct pool *pool, bool live, char *url, char *user, char *pass) { - struct pool *pool; - - pool = add_pool(); - url = get_proxy(url, pool); pool->rpc_url = url; @@ -5187,6 +5200,7 @@ void add_pool_details(bool live, char *url, char *user, char *pass) static bool input_pool(bool live) { char *url = NULL, *user = NULL, *pass = NULL; + struct pool *pool; bool ret = false; immedok(logwin, true); @@ -5196,7 +5210,18 @@ static bool input_pool(bool live) if (!url) goto out; - if (strncmp(url, "http://", 7) && + user = curses_input("Username"); + if (!user) + goto out; + + pass = curses_input("Password"); + if (!pass) + goto out; + + pool = add_pool(); + + if (!detect_stratum(pool, url) && + strncmp(url, "http://", 7) && strncmp(url, "https://", 8)) { char *httpinput; @@ -5209,15 +5234,7 @@ static bool input_pool(bool live) url = httpinput; } - user = curses_input("Username"); - if (!user) - goto out; - - pass = curses_input("Password"); - if (!pass) - goto out; - - add_pool_details(live, url, user, pass); + add_pool_details(pool, live, url, user, pass); ret = true; out: immedok(logwin, false); diff --git a/miner.h b/miner.h index f1a284e7..1fb71811 100644 --- a/miner.h +++ b/miner.h @@ -646,7 +646,9 @@ extern void api(int thr_id); extern struct pool *current_pool(void); extern int enabled_pools; -extern void add_pool_details(bool live, char *url, char *user, char *pass); +extern bool detect_stratum(struct pool *pool, char *url); +extern struct pool *add_pool(void); +extern void add_pool_details(struct pool *pool, bool live, char *url, char *user, char *pass); #define MAX_GPUDEVICES 16 @@ -818,6 +820,8 @@ struct pool { char *subscription; char *nonce1; int nonce2; + bool has_stratum; + bool stratum_active; }; #define GETWORK_MODE_TESTPOOL 'T' diff --git a/util.c b/util.c index c5d0f765..ae2063d2 100644 --- a/util.c +++ b/util.c @@ -972,9 +972,13 @@ out: CLOSESOCKET(pool->sock); if (val) json_decref(val); - } else if (opt_protocol) - applog(LOG_DEBUG, "Pool %d confirmed mining.notify with subscription %s extranonce1 %s extranonce2 %d", - pool->pool_no, pool->subscription, pool->nonce1, pool->nonce2); + } else { + pool->stratum_active = true; + if (opt_protocol) { + applog(LOG_DEBUG, "Pool %d confirmed mining.notify with subscription %s extranonce1 %s extranonce2 %d", + pool->pool_no, pool->subscription, pool->nonce1, pool->nonce2); + } + } return ret; } From 30b665f021d91e8d04b8ddaaf608267d9d1e13d1 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 27 Sep 2012 13:01:12 +1000 Subject: [PATCH 012/160] Test specifically for stratum being active in pool_active. --- cgminer.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cgminer.c b/cgminer.c index 85574acf..4f31b5dc 100644 --- a/cgminer.c +++ b/cgminer.c @@ -3967,6 +3967,14 @@ static bool pool_active(struct pool *pool, bool pinging) CURL *curl; int rolltime; + if (pool->has_stratum) { + if (pool->stratum_active && !pinging) + return true; + if (initiate_stratum(pool)) + return true; + return false; + } + curl = curl_easy_init(); if (unlikely(!curl)) { applog(LOG_ERR, "CURL initialisation failed"); From 64df34cd4e1bc1d74ff7b6ad803e03948e27b9cd Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 27 Sep 2012 13:26:09 +1000 Subject: [PATCH 013/160] Create a stratum work structure to store current work variables. --- miner.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/miner.h b/miner.h index 1fb71811..af5c4669 100644 --- a/miner.h +++ b/miner.h @@ -751,6 +751,26 @@ enum pool_enable { POOL_REJECTING, }; +struct stratum_work { + /* id we sent to receive this work */ + int id; + /* Reference to json structure all the following were extracted from */ + json_t *json_val; + + char *job_id; + char *prev_hash; + char *coinbase1; + char *coinbase2; + char *merkle1; + char *merkle2; + char *bbversion; + char *nbit; + char *ntime; + bool clean; + + int diff; +}; + struct pool { int pool_no; int prio; @@ -822,6 +842,7 @@ struct pool { int nonce2; bool has_stratum; bool stratum_active; + struct stratum_work swork; }; #define GETWORK_MODE_TESTPOOL 'T' From 07e6bd1262a1085c7ca295f0e0058dfd5f5fef0e Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 27 Sep 2012 13:50:05 +1000 Subject: [PATCH 014/160] Provide a helper function for reading a single \n terminated string from a socket. --- util.c | 54 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/util.c b/util.c index ae2063d2..b69cf230 100644 --- a/util.c +++ b/util.c @@ -863,6 +863,41 @@ static bool sock_send(int sock, char *s, ssize_t len) #define RECVSIZE 8192 +static void clear_sock(SOCKETTYPE sock) +{ + char *s = alloca(RECVSIZE); + + recv(sock, s, RECVSIZE, MSG_DONTWAIT); +} + +/* Peeks at a socket to find the first end of line and then reads just that + * from the socket and returns that as a malloced char */ +static char *recv_line(SOCKETTYPE sock) +{ + char *sret = NULL, *s; + ssize_t len; + + s = alloca(RECVSIZE); + if (SOCKETFAIL(recv(sock, s, RECVSIZE, MSG_PEEK))) { + applog(LOG_DEBUG, "Failed to recv sock in recv_line"); + goto out; + } + sret = strtok(s, "\n"); + if (!sret) { + applog(LOG_DEBUG, "Failed to parse a \\n terminated string in recv_line"); + goto out; + } + len = strlen(sret); + /* We know how much data is in the buffer so this read should not fail */ + read(sock, s, len); + sret = strdup(s); + +out: + if (!sret) + clear_sock(sock); + return sret; +} + bool initiate_stratum(struct pool *pool) { json_t *val, *res_val, *err_val, *notify_val; @@ -870,7 +905,6 @@ bool initiate_stratum(struct pool *pool) struct timeval timeout; json_error_t err; bool ret = false; - ssize_t len; fd_set rd; s = alloca(RECVSIZE); @@ -898,22 +932,12 @@ bool initiate_stratum(struct pool *pool) goto out; } - if (SOCKETFAIL(recv(pool->sock, s, RECVSIZE, MSG_PEEK | MSG_DONTWAIT))) { - applog(LOG_DEBUG, "Failed to recv sock in initiate_stratum"); + sret = recv_line(pool->sock); + if (!sret) goto out; - } - - sret = strtok(s, "\n"); - if (!sret) { - applog(LOG_DEBUG, "Failed to parse a \\n terminated string in initiate_stratum"); - goto out; - } - - /* We know how much data is in the buffer so this read should not fail */ - len = strlen(sret); - read(pool->sock, s, len); - val = JSON_LOADS(s, &err); + val = JSON_LOADS(sret, &err); + free(sret); if (!val) { applog(LOG_DEBUG, "JSON decode failed(%d): %s", err.line, err.text); goto out; From a6f1a62220ef161068bd6d437c0e0683e2dd1eb3 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 28 Sep 2012 04:35:16 +1000 Subject: [PATCH 015/160] Create helper functions for checking when a socket is ready to read on and receive a single line at a time. Begin stratum authorisation process. --- cgminer.c | 8 +++---- miner.h | 3 +++ util.c | 72 +++++++++++++++++++++++++++++++++++++++++++++---------- util.h | 1 + 4 files changed, 68 insertions(+), 16 deletions(-) diff --git a/cgminer.c b/cgminer.c index 4f31b5dc..ac4b85fe 100644 --- a/cgminer.c +++ b/cgminer.c @@ -3968,10 +3968,10 @@ static bool pool_active(struct pool *pool, bool pinging) int rolltime; if (pool->has_stratum) { - if (pool->stratum_active && !pinging) - return true; - if (initiate_stratum(pool)) - return true; + if ((!pool->stratum_active || pinging) && !initiate_stratum(pool)) + return false; + if (!pool->stratum_auth && !auth_stratum(pool)) + return false; return false; } diff --git a/miner.h b/miner.h index af5c4669..a255a6f0 100644 --- a/miner.h +++ b/miner.h @@ -842,6 +842,9 @@ struct pool { int nonce2; bool has_stratum; bool stratum_active; + bool stratum_auth; + /* Store json reference to clear it if we close connection */ + json_t *stratum_val; struct stratum_work swork; }; diff --git a/util.c b/util.c index b69cf230..25e9a933 100644 --- a/util.c +++ b/util.c @@ -850,6 +850,9 @@ static bool sock_send(int sock, char *s, ssize_t len) { ssize_t sent = 0; + if (opt_protocol) + applog(LOG_DEBUG, "SEND: %s", s); + while (len > 0 ) { sent = send(sock, s + sent, len, 0); if (SOCKETFAIL(sent)) @@ -870,6 +873,24 @@ static void clear_sock(SOCKETTYPE sock) recv(sock, s, RECVSIZE, MSG_DONTWAIT); } +/* Check to see if Santa's been good to you */ +static bool sock_full(SOCKETTYPE sock, bool wait) +{ + struct timeval timeout; + fd_set rd; + + FD_ZERO(&rd); + FD_SET(sock, &rd); + timeout.tv_usec = 0; + if (wait) + timeout.tv_sec = 60; + else + timeout.tv_sec = 0; + if (select(sock + 1, &rd, NULL, NULL, &timeout) > 0) + return true; + return false; +} + /* Peeks at a socket to find the first end of line and then reads just that * from the socket and returns that as a malloced char */ static char *recv_line(SOCKETTYPE sock) @@ -887,28 +908,58 @@ static char *recv_line(SOCKETTYPE sock) applog(LOG_DEBUG, "Failed to parse a \\n terminated string in recv_line"); goto out; } - len = strlen(sret); + len = strlen(sret) + 1; /* We know how much data is in the buffer so this read should not fail */ - read(sock, s, len); - sret = strdup(s); - + if (SOCKETFAIL(recv(sock, s, len, 0))) + goto out; + if (s) + sret = strdup(strtok(s, "\n")); out: if (!sret) clear_sock(sock); + else if (opt_protocol) + applog(LOG_DEBUG, "RECVD: %s", sret); return sret; } +bool auth_stratum(struct pool *pool) +{ + json_t *val = NULL, *res_val, *err_val, *notify_val; + char *s, *buf, *sret = NULL; + json_error_t err; + bool ret = false; + + s = alloca(RECVSIZE); + sprintf(s, "{\"id\": %d, \"method\": \"mining.authorize\", \"params\": [\"%s\", \"%s\"]}\n", + pool->swork.id++, pool->rpc_user, pool->rpc_pass); + + while (sock_full(pool->sock, false)) { + sret = recv_line(pool->sock); + free(sret); + } + + if (!sock_send(pool->sock, s, strlen(s))) + goto out; + +out: + if (!ret) { + if (val) + json_decref(val); + } else + pool->stratum_val = val; + + return ret; +} + bool initiate_stratum(struct pool *pool) { json_t *val, *res_val, *err_val, *notify_val; char *s, *buf, *sret = NULL; - struct timeval timeout; json_error_t err; bool ret = false; - fd_set rd; s = alloca(RECVSIZE); - sprintf(s, "{\"id\": 0, \"method\": \"mining.subscribe\", \"params\": []}\n"); + sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": []}\n", pool->swork.id++); pool->sock = socket(AF_INET, SOCK_STREAM, 0); if (pool->sock == INVSOCK) @@ -923,11 +974,7 @@ bool initiate_stratum(struct pool *pool) goto out; } - /* Use select to timeout instead of waiting forever for a response */ - FD_ZERO(&rd); - FD_SET(pool->sock, &rd); - timeout.tv_sec = 60; - if (select(pool->sock + 1, &rd, NULL, NULL, &timeout) < 1) { + if (!sock_full(pool->sock, true)) { applog(LOG_DEBUG, "Timed out waiting for response in initiate_stratum"); goto out; } @@ -998,6 +1045,7 @@ out: json_decref(val); } else { pool->stratum_active = true; + pool->stratum_val = val; if (opt_protocol) { applog(LOG_DEBUG, "Pool %d confirmed mining.notify with subscription %s extranonce1 %s extranonce2 %d", pool->pool_no, pool->subscription, pool->nonce1, pool->nonce2); diff --git a/util.h b/util.h index 72304fec..3962f039 100644 --- a/util.h +++ b/util.h @@ -110,6 +110,7 @@ #endif struct pool; bool extract_sockaddr(struct pool *pool, char *url); +bool auth_stratum(struct pool *pool); bool initiate_stratum(struct pool *pool); #endif /* __UTIL_H__ */ From 7e2dcc6fff6d55639e387f645dc674f12c87f870 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 28 Sep 2012 05:16:52 +1000 Subject: [PATCH 016/160] Create parse_stratum function that hands off stratum parameters to other functions to manage pool stratum work struct variables. Implement mining difficulty setting. --- util.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 3 deletions(-) diff --git a/util.c b/util.c index 25e9a933..09c351b0 100644 --- a/util.c +++ b/util.c @@ -922,9 +922,86 @@ out: return sret; } +static bool parse_notify(struct pool *pool, json_t *val) +{ + return true; +} + +static bool parse_diff(struct pool *pool, json_t *val) +{ + int diff; + + diff = json_integer_value(json_array_get(val, 0)); + if (diff < 1) + return false; + + mutex_lock(&pool->pool_lock); + pool->swork.diff = diff; + mutex_unlock(&pool->pool_lock); + + applog(LOG_DEBUG, "Pool %d difficulty set to %d", pool->pool_no, diff); + + return true; +} + +static bool parse_stratum(struct pool *pool, char *s) +{ + json_t *val = NULL, *method, *err_val, *params; + json_error_t err; + bool ret = false; + char *buf; + + val = JSON_LOADS(s, &err); + if (!val) { + applog(LOG_INFO, "JSON decode failed(%d): %s", err.line, err.text); + goto out; + } + + method = json_object_get(val, "method"); + err_val = json_object_get(val, "error"); + params = json_object_get(val, "params"); + + if (!method || json_is_null(method) || + (err_val && !json_is_null(err_val))) { + char *ss; + + if (err_val) + ss = json_dumps(err_val, JSON_INDENT(3)); + else + ss = strdup("(unknown reason)"); + + applog(LOG_INFO, "JSON-RPC decode failed: %s", ss); + + free(ss); + + goto out; + } + + buf = (char *)json_string_value(method); + if (!buf) + goto out; + + if (!strncasecmp(buf, "mining.notify", 13) && parse_notify(pool, params)) { + ret = true; + goto out; + } + + if (!strncasecmp(buf, "mining.set_difficulty", 21) && parse_diff(pool, params)) { + ret = true; + goto out; + } + +out: + if (!ret) { + if (val) + json_decref(val); + } + return ret; +} + bool auth_stratum(struct pool *pool) { - json_t *val = NULL, *res_val, *err_val, *notify_val; + json_t *val = NULL, *res_val, *err_val; char *s, *buf, *sret = NULL; json_error_t err; bool ret = false; @@ -935,6 +1012,7 @@ bool auth_stratum(struct pool *pool) while (sock_full(pool->sock, false)) { sret = recv_line(pool->sock); + parse_stratum(pool, sret); free(sret); } @@ -986,7 +1064,7 @@ bool initiate_stratum(struct pool *pool) val = JSON_LOADS(sret, &err); free(sret); if (!val) { - applog(LOG_DEBUG, "JSON decode failed(%d): %s", err.line, err.text); + applog(LOG_INFO, "JSON decode failed(%d): %s", err.line, err.text); goto out; } @@ -1002,7 +1080,7 @@ bool initiate_stratum(struct pool *pool) else ss = strdup("(unknown reason)"); - applog(LOG_INFO, "JSON-RPC call failed: %s", ss); + applog(LOG_INFO, "JSON-RPC decode failed: %s", ss); free(ss); From d416d22381e3431507fb849f97a3a60f98b84e5a Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 28 Sep 2012 05:26:29 +1000 Subject: [PATCH 017/160] Don't keep any json references around with stratum structures. --- util.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/util.c b/util.c index 09c351b0..db100ecc 100644 --- a/util.c +++ b/util.c @@ -992,10 +992,9 @@ static bool parse_stratum(struct pool *pool, char *s) } out: - if (!ret) { - if (val) - json_decref(val); - } + if (val) + json_decref(val); + return ret; } @@ -1020,11 +1019,8 @@ bool auth_stratum(struct pool *pool) goto out; out: - if (!ret) { - if (val) - json_decref(val); - } else - pool->stratum_val = val; + if (val) + json_decref(val); return ret; } @@ -1098,13 +1094,13 @@ bool initiate_stratum(struct pool *pool) applog(LOG_WARNING, "Failed to get mining notify in initiate_stratum"); goto out; } - pool->subscription = (char *)json_string_value(json_array_get(notify_val, 1)); + pool->subscription = strdup(json_string_value(json_array_get(notify_val, 1))); if (!pool->subscription) { applog(LOG_WARNING, "Failed to get a subscription in initiate_stratum"); goto out; } - pool->nonce1 = (char *)json_string_value(json_array_get(res_val, 1)); + pool->nonce1 = strdup(json_string_value(json_array_get(res_val, 1))); if (!pool->nonce1) { applog(LOG_WARNING, "Failed to get nonce1 in initiate_stratum"); goto out; @@ -1117,18 +1113,18 @@ bool initiate_stratum(struct pool *pool) ret = true; out: - if (!ret) { - CLOSESOCKET(pool->sock); - if (val) - json_decref(val); - } else { + if (val) + json_decref(val); + + if (ret) { pool->stratum_active = true; pool->stratum_val = val; if (opt_protocol) { applog(LOG_DEBUG, "Pool %d confirmed mining.notify with subscription %s extranonce1 %s extranonce2 %d", pool->pool_no, pool->subscription, pool->nonce1, pool->nonce2); } - } + } else + CLOSESOCKET(pool->sock); return ret; } From b86a893981a29da01f53d9b41e0037f7195f88e5 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 28 Sep 2012 05:30:36 +1000 Subject: [PATCH 018/160] Append \n in the sock_send function instead of adding it when constructing json in stratum. --- util.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/util.c b/util.c index db100ecc..d97fc906 100644 --- a/util.c +++ b/util.c @@ -846,6 +846,7 @@ bool extract_sockaddr(struct pool *pool, char *url) return true; } +/* Send a single command across a socket, appending \n to it */ static bool sock_send(int sock, char *s, ssize_t len) { ssize_t sent = 0; @@ -853,6 +854,9 @@ static bool sock_send(int sock, char *s, ssize_t len) if (opt_protocol) applog(LOG_DEBUG, "SEND: %s", s); + strcat(s, "\n"); + len++; + while (len > 0 ) { sent = send(sock, s + sent, len, 0); if (SOCKETFAIL(sent)) @@ -1006,7 +1010,7 @@ bool auth_stratum(struct pool *pool) bool ret = false; s = alloca(RECVSIZE); - sprintf(s, "{\"id\": %d, \"method\": \"mining.authorize\", \"params\": [\"%s\", \"%s\"]}\n", + sprintf(s, "{\"id\": %d, \"method\": \"mining.authorize\", \"params\": [\"%s\", \"%s\"]}", pool->swork.id++, pool->rpc_user, pool->rpc_pass); while (sock_full(pool->sock, false)) { @@ -1033,7 +1037,7 @@ bool initiate_stratum(struct pool *pool) bool ret = false; s = alloca(RECVSIZE); - sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": []}\n", pool->swork.id++); + sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": []}", pool->swork.id++); pool->sock = socket(AF_INET, SOCK_STREAM, 0); if (pool->sock == INVSOCK) From 9d4a44e88e01bed91ffac5b70a491db21783e71b Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 28 Sep 2012 09:57:42 +1000 Subject: [PATCH 019/160] Create helper functions for duplicating json strings to avoid keeping json references in use. --- miner.h | 4 ---- util.c | 40 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/miner.h b/miner.h index a255a6f0..c099012e 100644 --- a/miner.h +++ b/miner.h @@ -754,8 +754,6 @@ enum pool_enable { struct stratum_work { /* id we sent to receive this work */ int id; - /* Reference to json structure all the following were extracted from */ - json_t *json_val; char *job_id; char *prev_hash; @@ -843,8 +841,6 @@ struct pool { bool has_stratum; bool stratum_active; bool stratum_auth; - /* Store json reference to clear it if we close connection */ - json_t *stratum_val; struct stratum_work swork; }; diff --git a/util.c b/util.c index d97fc906..32ca0e69 100644 --- a/util.c +++ b/util.c @@ -926,8 +926,41 @@ out: return sret; } +/* Extracts a string value from a json array with error checking. To be used + * when the value of the string returned is only examined and not to be stored. + * See json_array_string below */ +static char *__json_array_string(json_t *val, unsigned int entry) +{ + json_t *arr_entry; + + if (json_is_null(val)) + return NULL; + if (!json_is_array(val)) + return NULL; + if (entry > json_array_size(val)) + return NULL; + arr_entry = json_array_get(val, entry); + if (!json_is_string(arr_entry)) + return NULL; + + return (json_string_value(arr_entry)); +} + +/* Creates a freshly malloced dup of __json_array_string */ +static char *json_array_string(json_t *val, unsigned int entry) +{ + char *buf = __json_array_string(val, entry); + + if (buf) + return strdup(buf); + return NULL; +} + static bool parse_notify(struct pool *pool, json_t *val) { + json_t *arr; + + return true; } @@ -1093,18 +1126,18 @@ bool initiate_stratum(struct pool *pool) goto out; } - buf = (char *)json_string_value(json_array_get(notify_val, 0)); + buf = __json_array_string(notify_val, 0); if (!buf || strcasecmp(buf, "mining.notify")) { applog(LOG_WARNING, "Failed to get mining notify in initiate_stratum"); goto out; } - pool->subscription = strdup(json_string_value(json_array_get(notify_val, 1))); + pool->subscription = json_array_string(notify_val, 1); if (!pool->subscription) { applog(LOG_WARNING, "Failed to get a subscription in initiate_stratum"); goto out; } - pool->nonce1 = strdup(json_string_value(json_array_get(res_val, 1))); + pool->nonce1 = json_array_string(res_val, 1); if (!pool->nonce1) { applog(LOG_WARNING, "Failed to get nonce1 in initiate_stratum"); goto out; @@ -1122,7 +1155,6 @@ out: if (ret) { pool->stratum_active = true; - pool->stratum_val = val; if (opt_protocol) { applog(LOG_DEBUG, "Pool %d confirmed mining.notify with subscription %s extranonce1 %s extranonce2 %d", pool->pool_no, pool->subscription, pool->nonce1, pool->nonce2); From 331026595f6fb17c662b269fb7fc70ec390d7186 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 28 Sep 2012 10:18:58 +1000 Subject: [PATCH 020/160] Implement stratum parsing of notify parameters and storing them in the pool stratum work structure. --- util.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/util.c b/util.c index 32ca0e69..211cc1c1 100644 --- a/util.c +++ b/util.c @@ -943,7 +943,7 @@ static char *__json_array_string(json_t *val, unsigned int entry) if (!json_is_string(arr_entry)) return NULL; - return (json_string_value(arr_entry)); + return (char *)json_string_value(arr_entry); } /* Creates a freshly malloced dup of __json_array_string */ @@ -958,9 +958,76 @@ static char *json_array_string(json_t *val, unsigned int entry) static bool parse_notify(struct pool *pool, json_t *val) { + char *job_id, *prev_hash, *coinbase1, *coinbase2, *merkle1, *merkle2, + *bbversion, *nbit, *ntime; json_t *arr; + bool clean; + + arr = json_array_get(val, 4); + if (!arr || !json_is_array(arr)) + return false; + + job_id = json_array_string(val, 0); + prev_hash = json_array_string(val, 1); + coinbase1 = json_array_string(val, 2); + coinbase2 = json_array_string(val, 3); + merkle1 = json_array_string(arr, 0); + merkle2 = json_array_string(arr, 1); + bbversion = json_array_string(val, 5); + nbit = json_array_string(val, 6); + ntime = json_array_string(val, 7); + clean = json_is_true(json_array_get(val, 8)); + + if (!job_id || !prev_hash || !coinbase1 || !coinbase2 || !merkle1 || + !merkle2 || !bbversion || !nbit || !ntime) { + /* Annoying but we must not leak memory */ + if (job_id) + free(job_id); + if (prev_hash) + free(prev_hash); + if (coinbase1) + free(coinbase1); + if (coinbase2) + free(coinbase2); + if (merkle1) + free(merkle1); + if (merkle2) + free(merkle2); + if (bbversion) + free(bbversion); + if (nbit) + free(nbit); + if (ntime) + free(ntime); + return false; + } + + mutex_lock(&pool->pool_lock); + pool->swork.job_id = job_id; + pool->swork.prev_hash = prev_hash; + pool->swork.coinbase1 = coinbase1; + pool->swork.coinbase2 = coinbase2; + pool->swork.merkle1 = merkle1; + pool->swork.merkle2 = merkle2; + pool->swork.bbversion = bbversion; + pool->swork.nbit = nbit; + pool->swork.ntime = ntime; + pool->swork.clean = clean; + mutex_unlock(&pool->pool_lock); + + if (opt_protocol) { + applog(LOG_DEBUG, "job_id: %s", job_id); + applog(LOG_DEBUG, "prev_hash: %s", prev_hash); + applog(LOG_DEBUG, "coinbase1: %s", coinbase1); + applog(LOG_DEBUG, "coinbase2: %s", coinbase2); + applog(LOG_DEBUG, "merkle1: %s", merkle1); + applog(LOG_DEBUG, "merkle2: %s", merkle2); + applog(LOG_DEBUG, "bbversion: %s", bbversion); + applog(LOG_DEBUG, "nbit: %s", nbit); + applog(LOG_DEBUG, "ntime: %s", ntime); + applog(LOG_DEBUG, "clean: %s", clean ? "yes" : "no"); + } - return true; } From ac9a4378d1e32ac51d054185ac6746fab771ff2c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 28 Sep 2012 10:31:45 +1000 Subject: [PATCH 021/160] Complete authorisation in stratum. --- util.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/util.c b/util.c index 211cc1c1..54f795e9 100644 --- a/util.c +++ b/util.c @@ -1105,7 +1105,7 @@ out: bool auth_stratum(struct pool *pool) { json_t *val = NULL, *res_val, *err_val; - char *s, *buf, *sret = NULL; + char *s, *sret = NULL; json_error_t err; bool ret = false; @@ -1113,6 +1113,7 @@ bool auth_stratum(struct pool *pool) sprintf(s, "{\"id\": %d, \"method\": \"mining.authorize\", \"params\": [\"%s\", \"%s\"]}", pool->swork.id++, pool->rpc_user, pool->rpc_pass); + /* Parse all data prior sending auth request */ while (sock_full(pool->sock, false)) { sret = recv_line(pool->sock); parse_stratum(pool, sret); @@ -1122,10 +1123,34 @@ bool auth_stratum(struct pool *pool) if (!sock_send(pool->sock, s, strlen(s))) goto out; + sret = recv_line(pool->sock); + if (!sret) + goto out; + val = JSON_LOADS(sret, &err); + free(sret); + res_val = json_object_get(val, "result"); + err_val = json_object_get(val, "error"); + + if (!res_val || json_is_false(res_val) || (err_val && !json_is_null(err_val))) { + char *ss; + + if (err_val) + ss = json_dumps(err_val, JSON_INDENT(3)); + else + ss = strdup("(unknown reason)"); + applog(LOG_WARNING, "JSON stratum auth failed: %s", ss); + free(ss); + + goto out; + } + ret = true; + applog(LOG_INFO, "Stratum authorisation success for pool %d", pool->pool_no); out: if (val) json_decref(val); + pool->stratum_auth = ret; + return ret; } From 31c3759ecdee5db19a589640250a6deddbc93f06 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 28 Sep 2012 10:37:42 +1000 Subject: [PATCH 022/160] Check return value of stratum_parse. --- util.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/util.c b/util.c index 54f795e9..0aeadf6a 100644 --- a/util.c +++ b/util.c @@ -1116,7 +1116,12 @@ bool auth_stratum(struct pool *pool) /* Parse all data prior sending auth request */ while (sock_full(pool->sock, false)) { sret = recv_line(pool->sock); - parse_stratum(pool, sret); + if (!parse_stratum(pool, sret)) { + clear_sock(pool->sock); + applog(LOG_WARNING, "Failed to parse stratum buffer"); + free(sret); + return ret; + } free(sret); } From 56255a0c86064c3b7810f6892e136f93076ae9cd Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 28 Sep 2012 18:01:33 +1000 Subject: [PATCH 023/160] Create a stratum thread per pool that has stratum that monitors the socket and serves received data. --- cgminer.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++---- miner.h | 1 + util.c | 4 ++-- util.h | 2 ++ 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/cgminer.c b/cgminer.c index ac4b85fe..0aba950a 100644 --- a/cgminer.c +++ b/cgminer.c @@ -3957,6 +3957,50 @@ out_unlock: } } +/* 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 + * side will eventually expire data it fails to send. */ +static void *stratum_thread(void *userdata) +{ + struct pool *pool = (struct pool *)userdata; + SOCKETTYPE sock = pool->sock; + fd_set rd; + + pthread_detach(pthread_self()); + + FD_ZERO(&rd); + FD_SET(sock, &rd); + + while (42) { + char *s; + + if (select(sock + 1, &rd, NULL, NULL, NULL) < 0) { + pool->stratum_active = pool->stratum_auth = false; + applog(LOG_WARNING, "Stratum connection to pool %d interrupted", pool->pool_no); + pool->getfail_occasions++; + if (!initiate_stratum(pool) || !auth_stratum(pool)) { + pool_died(pool); + break; + } + } + s = recv_line(sock); + if (unlikely(!s)) + continue; + if (!parse_stratum(pool, s)) /* Create message queues here */ + applog(LOG_INFO, "Unknown stratum msg: %s", s); + free(s); + } + + return NULL; +} + +static void init_stratum_thread(struct pool *pool) +{ + if (unlikely(pthread_create(&pool->stratum_thread, NULL, stratum_thread, (void *)pool))) + quit(1, "Failed to create stratum thread"); +} + static void *longpoll_thread(void *userdata); static bool pool_active(struct pool *pool, bool pinging) @@ -3970,9 +4014,15 @@ static bool pool_active(struct pool *pool, bool pinging) if (pool->has_stratum) { if ((!pool->stratum_active || pinging) && !initiate_stratum(pool)) return false; - if (!pool->stratum_auth && !auth_stratum(pool)) - return false; - return false; + if (!pool->stratum_auth) { + if (!auth_stratum(pool)) + return false; + /* We create the stratum thread for each pool just + * after successful authorisation */ + init_stratum_thread(pool); + return true; + } + return true; } curl = curl_easy_init(); @@ -5473,7 +5523,9 @@ int main(int argc, char *argv[]) sigemptyset(&handler.sa_mask); sigaction(SIGTERM, &handler, &termhandler); sigaction(SIGINT, &handler, &inthandler); - +#ifndef WIN32 + signal(SIGPIPE, SIG_IGN); +#endif opt_kernel_path = alloca(PATH_MAX); strcpy(opt_kernel_path, CGMINER_PREFIX); cgminer_path = alloca(PATH_MAX); diff --git a/miner.h b/miner.h index c099012e..fc4ba8c5 100644 --- a/miner.h +++ b/miner.h @@ -842,6 +842,7 @@ struct pool { bool stratum_active; bool stratum_auth; struct stratum_work swork; + pthread_t stratum_thread; }; #define GETWORK_MODE_TESTPOOL 'T' diff --git a/util.c b/util.c index 0aeadf6a..aa5c709d 100644 --- a/util.c +++ b/util.c @@ -897,7 +897,7 @@ static bool sock_full(SOCKETTYPE sock, bool wait) /* Peeks at a socket to find the first end of line and then reads just that * from the socket and returns that as a malloced char */ -static char *recv_line(SOCKETTYPE sock) +char *recv_line(SOCKETTYPE sock) { char *sret = NULL, *s; ssize_t len; @@ -1048,7 +1048,7 @@ static bool parse_diff(struct pool *pool, json_t *val) return true; } -static bool parse_stratum(struct pool *pool, char *s) +bool parse_stratum(struct pool *pool, char *s) { json_t *val = NULL, *method, *err_val, *params; json_error_t err; diff --git a/util.h b/util.h index 3962f039..4eb51a70 100644 --- a/util.h +++ b/util.h @@ -109,6 +109,8 @@ #endif #endif struct pool; +char *recv_line(SOCKETTYPE sock); +bool parse_stratum(struct pool *pool, char *s); bool extract_sockaddr(struct pool *pool, char *url); bool auth_stratum(struct pool *pool); bool initiate_stratum(struct pool *pool); From 0f1f2a62a69233c1c4de087899a6f3d41d91b554 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 28 Sep 2012 18:04:28 +1000 Subject: [PATCH 024/160] Use the pool sock value directly in the stratum thread in case it changes after reconnecting. --- cgminer.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/cgminer.c b/cgminer.c index 0aba950a..6a8e0950 100644 --- a/cgminer.c +++ b/cgminer.c @@ -3964,18 +3964,17 @@ out_unlock: static void *stratum_thread(void *userdata) { struct pool *pool = (struct pool *)userdata; - SOCKETTYPE sock = pool->sock; - fd_set rd; pthread_detach(pthread_self()); - FD_ZERO(&rd); - FD_SET(sock, &rd); - while (42) { + fd_set rd; char *s; - if (select(sock + 1, &rd, NULL, NULL, NULL) < 0) { + FD_ZERO(&rd); + FD_SET(pool->sock, &rd); + + if (select(pool->sock + 1, &rd, NULL, NULL, NULL) < 0) { pool->stratum_active = pool->stratum_auth = false; applog(LOG_WARNING, "Stratum connection to pool %d interrupted", pool->pool_no); pool->getfail_occasions++; @@ -3984,7 +3983,7 @@ static void *stratum_thread(void *userdata) break; } } - s = recv_line(sock); + s = recv_line(pool->sock); if (unlikely(!s)) continue; if (!parse_stratum(pool, s)) /* Create message queues here */ From 04551445f6f63647f0b96bacfb472d7e43ca952a Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 29 Sep 2012 00:23:27 +1000 Subject: [PATCH 025/160] Cope with pools being removed in the stratum thread. --- cgminer.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/cgminer.c b/cgminer.c index 6a8e0950..94731219 100644 --- a/cgminer.c +++ b/cgminer.c @@ -3978,9 +3978,13 @@ static void *stratum_thread(void *userdata) pool->stratum_active = pool->stratum_auth = false; applog(LOG_WARNING, "Stratum connection to pool %d interrupted", pool->pool_no); pool->getfail_occasions++; - if (!initiate_stratum(pool) || !auth_stratum(pool)) { - pool_died(pool); - break; + total_go++; + while (!initiate_stratum(pool) || !auth_stratum(pool)) { + if (!pool->idle) + pool_died(pool); + if (pool->removed) + goto out; + sleep(5); } } s = recv_line(pool->sock); @@ -3989,8 +3993,14 @@ static void *stratum_thread(void *userdata) if (!parse_stratum(pool, s)) /* Create message queues here */ applog(LOG_INFO, "Unknown stratum msg: %s", s); free(s); + + if (unlikely(pool->removed)) { + CLOSESOCKET(pool->sock); + goto out; + } } +out: return NULL; } From 54ab28fd6e4f7b2822cdf728871af23e8a48cd3c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 29 Sep 2012 00:38:09 +1000 Subject: [PATCH 026/160] Provide rudimentary support for stratum clean work command in the stratum thread. --- cgminer.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cgminer.c b/cgminer.c index 94731219..e880c486 100644 --- a/cgminer.c +++ b/cgminer.c @@ -3993,6 +3993,11 @@ static void *stratum_thread(void *userdata) if (!parse_stratum(pool, s)) /* Create message queues here */ applog(LOG_INFO, "Unknown stratum msg: %s", s); free(s); + if (unlikely(pool->swork.clean)) { + pool->swork.clean = false; + applog(LOG_NOTICE, "Stratum requested work restart for block change"); + restart_threads(); + } if (unlikely(pool->removed)) { CLOSESOCKET(pool->sock); From 1221a80d414cd0187ec1edffb00d9a410effd189 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 29 Sep 2012 01:03:23 +1000 Subject: [PATCH 027/160] Rename nonce2 to n2size reflecting that it's a size variable and not the actual nonce. --- miner.h | 2 +- util.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/miner.h b/miner.h index fc4ba8c5..79cf5509 100644 --- a/miner.h +++ b/miner.h @@ -837,7 +837,7 @@ struct pool { struct sockaddr_in *server, client; char *subscription; char *nonce1; - int nonce2; + int n2size; bool has_stratum; bool stratum_active; bool stratum_auth; diff --git a/util.c b/util.c index aa5c709d..de2ff196 100644 --- a/util.c +++ b/util.c @@ -1239,9 +1239,9 @@ bool initiate_stratum(struct pool *pool) applog(LOG_WARNING, "Failed to get nonce1 in initiate_stratum"); goto out; } - pool->nonce2 = json_integer_value(json_array_get(res_val, 2)); - if (!pool->nonce2) { - applog(LOG_WARNING, "Failed to get nonce2 in initiate_stratum"); + pool->n2size = json_integer_value(json_array_get(res_val, 2)); + if (!pool->n2size) { + applog(LOG_WARNING, "Failed to get n2size in initiate_stratum"); goto out; } @@ -1253,8 +1253,8 @@ out: if (ret) { pool->stratum_active = true; if (opt_protocol) { - applog(LOG_DEBUG, "Pool %d confirmed mining.notify with subscription %s extranonce1 %s extranonce2 %d", - pool->pool_no, pool->subscription, pool->nonce1, pool->nonce2); + applog(LOG_DEBUG, "Pool %d confirmed mining.notify with subscription %s extranonce1 %s extran2size %d", + pool->pool_no, pool->subscription, pool->nonce1, pool->n2size); } } else CLOSESOCKET(pool->sock); From 1f64491f62daf348b72cb4ff84f5ba8c5565fe3b Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 29 Sep 2012 01:48:01 +1000 Subject: [PATCH 028/160] The number of transactions is variable so make merkle a variable length dynamically allocated array and track how many there are for stratum. --- miner.h | 4 ++-- util.c | 29 +++++++++++++++-------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/miner.h b/miner.h index 79cf5509..9efbedc2 100644 --- a/miner.h +++ b/miner.h @@ -759,13 +759,13 @@ struct stratum_work { char *prev_hash; char *coinbase1; char *coinbase2; - char *merkle1; - char *merkle2; + char **merkle; char *bbversion; char *nbit; char *ntime; bool clean; + int merkles; int diff; }; diff --git a/util.c b/util.c index de2ff196..75f8e6bd 100644 --- a/util.c +++ b/util.c @@ -958,8 +958,8 @@ static char *json_array_string(json_t *val, unsigned int entry) static bool parse_notify(struct pool *pool, json_t *val) { - char *job_id, *prev_hash, *coinbase1, *coinbase2, *merkle1, *merkle2, - *bbversion, *nbit, *ntime; + char *job_id, *prev_hash, *coinbase1, *coinbase2, *bbversion, *nbit, *ntime; + int merkles, i; json_t *arr; bool clean; @@ -967,19 +967,18 @@ static bool parse_notify(struct pool *pool, json_t *val) if (!arr || !json_is_array(arr)) return false; + merkles = json_array_size(arr); + job_id = json_array_string(val, 0); prev_hash = json_array_string(val, 1); coinbase1 = json_array_string(val, 2); coinbase2 = json_array_string(val, 3); - merkle1 = json_array_string(arr, 0); - merkle2 = json_array_string(arr, 1); bbversion = json_array_string(val, 5); nbit = json_array_string(val, 6); ntime = json_array_string(val, 7); clean = json_is_true(json_array_get(val, 8)); - if (!job_id || !prev_hash || !coinbase1 || !coinbase2 || !merkle1 || - !merkle2 || !bbversion || !nbit || !ntime) { + if (!job_id || !prev_hash || !coinbase1 || !coinbase2 || !bbversion || !nbit || !ntime) { /* Annoying but we must not leak memory */ if (job_id) free(job_id); @@ -989,10 +988,6 @@ static bool parse_notify(struct pool *pool, json_t *val) free(coinbase1); if (coinbase2) free(coinbase2); - if (merkle1) - free(merkle1); - if (merkle2) - free(merkle2); if (bbversion) free(bbversion); if (nbit) @@ -1007,12 +1002,18 @@ static bool parse_notify(struct pool *pool, json_t *val) pool->swork.prev_hash = prev_hash; pool->swork.coinbase1 = coinbase1; pool->swork.coinbase2 = coinbase2; - pool->swork.merkle1 = merkle1; - pool->swork.merkle2 = merkle2; pool->swork.bbversion = bbversion; pool->swork.nbit = nbit; pool->swork.ntime = ntime; pool->swork.clean = clean; + for (i = 0; i < pool->swork.merkles; i++) + free(pool->swork.merkle[i]); + if (merkles) { + pool->swork.merkle = realloc(pool->swork.merkle, sizeof(char *) * merkles + 1); + for (i = 0; i < merkles; i++) + pool->swork.merkle[i] = json_array_string(arr, i); + } + pool->swork.merkles = merkles; mutex_unlock(&pool->pool_lock); if (opt_protocol) { @@ -1020,8 +1021,8 @@ static bool parse_notify(struct pool *pool, json_t *val) applog(LOG_DEBUG, "prev_hash: %s", prev_hash); applog(LOG_DEBUG, "coinbase1: %s", coinbase1); applog(LOG_DEBUG, "coinbase2: %s", coinbase2); - applog(LOG_DEBUG, "merkle1: %s", merkle1); - applog(LOG_DEBUG, "merkle2: %s", merkle2); + for (i = 0; i < merkles; i++) + applog(LOG_DEBUG, "merkle%d: %s", i, pool->swork.merkle[i]); applog(LOG_DEBUG, "bbversion: %s", bbversion); applog(LOG_DEBUG, "nbit: %s", nbit); applog(LOG_DEBUG, "ntime: %s", ntime); From 1f6fe55152f73fd617e5fdfd387784b986822d26 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 29 Sep 2012 02:16:22 +1000 Subject: [PATCH 029/160] Generate the coinbase for generation of stratum based work. --- cgminer.c | 27 +++++++++++++++++++++++++++ miner.h | 1 + util.c | 2 ++ 3 files changed, 30 insertions(+) diff --git a/cgminer.c b/cgminer.c index e880c486..56d7dcaa 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4265,6 +4265,28 @@ static struct work *clone_work(struct work *work) return work; } +static void gen_stratum_work(struct pool *pool, struct work *work) +{ + char *coinbase, *nonce2; + int len; + + mutex_lock(&pool->pool_lock); + len = strlen(pool->swork.coinbase1) + + strlen(pool->nonce1) + + pool->n2size + + strlen(pool->swork.coinbase2); + coinbase = alloca(len + 1); + sprintf(coinbase, "%s", pool->swork.coinbase1); + strcat(coinbase, pool->nonce1); + nonce2 = bin2hex((const unsigned char *)&pool->nonce2, pool->n2size); + pool->nonce2++; + strcat(coinbase, nonce2); + free(nonce2); + strcat(coinbase, pool->swork.coinbase2); + mutex_unlock(&pool->pool_lock); + applog(LOG_DEBUG, "Generated stratum coinbase %s", coinbase); +} + static void get_work(struct work *work, struct thr_info *thr, const int thr_id) { struct timespec abstime = {0, 0}; @@ -4284,6 +4306,11 @@ static void get_work(struct work *work, struct thr_info *thr, const int thr_id) retry: pool = current_pool(); + if (pool->has_stratum) { + gen_stratum_work(pool, work); + goto out; + } + if (reuse_work(work)) goto out; diff --git a/miner.h b/miner.h index 9efbedc2..28d102af 100644 --- a/miner.h +++ b/miner.h @@ -837,6 +837,7 @@ struct pool { struct sockaddr_in *server, client; char *subscription; char *nonce1; + uint32_t nonce2; int n2size; bool has_stratum; bool stratum_active; diff --git a/util.c b/util.c index 75f8e6bd..0c75bb57 100644 --- a/util.c +++ b/util.c @@ -1014,6 +1014,8 @@ static bool parse_notify(struct pool *pool, json_t *val) pool->swork.merkle[i] = json_array_string(arr, i); } pool->swork.merkles = merkles; + if (clean) + pool->nonce2 = 0; mutex_unlock(&pool->pool_lock); if (opt_protocol) { From 5c74be5930bc93e7a254dd51feff4541015aa487 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 29 Sep 2012 10:30:56 +1000 Subject: [PATCH 030/160] Generate merkle root hash in gen_stratum_work. --- cgminer.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 56d7dcaa..67658a1b 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4265,12 +4265,24 @@ static struct work *clone_work(struct work *work) return work; } +static void gen_hash(unsigned char *data, unsigned char *hash, int len) +{ + unsigned char hash1[32]; + + sha2(data, len, hash1, false); + sha2(hash1, 32, hash, false); +} + static void gen_stratum_work(struct pool *pool, struct work *work) { + unsigned char merkle_root[32], merkle_sha[64], *merkle_hash; char *coinbase, *nonce2; - int len; + uint32_t *data32, *swap32; + int len, i; mutex_lock(&pool->pool_lock); + + /* Generate coinbase */ len = strlen(pool->swork.coinbase1) + strlen(pool->nonce1) + pool->n2size + @@ -4283,8 +4295,27 @@ static void gen_stratum_work(struct pool *pool, struct work *work) strcat(coinbase, nonce2); free(nonce2); strcat(coinbase, pool->swork.coinbase2); + + /* Generate merkle root */ + gen_hash((unsigned char *)coinbase, merkle_root, len); + memcpy(merkle_sha, merkle_root, 32); + for (i = 0; i < pool->swork.merkles; i++) { + memcpy(merkle_sha + 32, pool->swork.merkle[i], 32); + gen_hash(merkle_sha, merkle_root, 64); + memcpy(merkle_sha, merkle_root, 32); + } + data32 = (uint32_t *)merkle_sha; + swap32 = (uint32_t *)merkle_root; + for (i = 0; i < 32 / 4; i++) + swap32[i] = swab32(data32[i]); + merkle_hash = (unsigned char *)bin2hex((const unsigned char *)merkle_root, 32); + mutex_unlock(&pool->pool_lock); + applog(LOG_DEBUG, "Generated stratum coinbase %s", coinbase); + applog(LOG_DEBUG, "Generated stratum merkle %s", merkle_hash); + + free(merkle_hash); } static void get_work(struct work *work, struct thr_info *thr, const int thr_id) From e1468cc5fd37c399142807b7877998df32dce9a8 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 29 Sep 2012 11:02:25 +1000 Subject: [PATCH 031/160] Generate header created from stratum structures in gen_stratum_work. --- cgminer.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 67658a1b..a65bf54c 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4276,7 +4276,7 @@ static void gen_hash(unsigned char *data, unsigned char *hash, int len) static void gen_stratum_work(struct pool *pool, struct work *work) { unsigned char merkle_root[32], merkle_sha[64], *merkle_hash; - char *coinbase, *nonce2; + char header[256], *coinbase, *nonce2; uint32_t *data32, *swap32; int len, i; @@ -4310,10 +4310,19 @@ static void gen_stratum_work(struct pool *pool, struct work *work) swap32[i] = swab32(data32[i]); merkle_hash = (unsigned char *)bin2hex((const unsigned char *)merkle_root, 32); + sprintf(header, "%s", pool->swork.bbversion); + strcat(header, pool->swork.prev_hash); + strcat(header, (char *)merkle_hash); + strcat(header, pool->swork.ntime); + strcat(header, pool->swork.nbit); + strcat(header, "00000000"); /* nonce */ + strcat(header, "000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000"); + mutex_unlock(&pool->pool_lock); applog(LOG_DEBUG, "Generated stratum coinbase %s", coinbase); applog(LOG_DEBUG, "Generated stratum merkle %s", merkle_hash); + applog(LOG_DEBUG, "Generated stratum header %s", header); free(merkle_hash); } From 2e9ade14a9d17cea68d401b9be778743e8610a52 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 29 Sep 2012 11:12:59 +1000 Subject: [PATCH 032/160] Generate work data, midstate and hash1 in gen_stratum_work. --- cgminer.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index a65bf54c..58e5177d 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4276,9 +4276,9 @@ static void gen_hash(unsigned char *data, unsigned char *hash, int len) static void gen_stratum_work(struct pool *pool, struct work *work) { unsigned char merkle_root[32], merkle_sha[64], *merkle_hash; - char header[256], *coinbase, *nonce2; + char header[256], hash1[128], *coinbase, *nonce2; uint32_t *data32, *swap32; - int len, i; + int len, i, diff; mutex_lock(&pool->pool_lock); @@ -4318,6 +4318,8 @@ static void gen_stratum_work(struct pool *pool, struct work *work) strcat(header, "00000000"); /* nonce */ strcat(header, "000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000"); + diff = pool->swork.diff; + mutex_unlock(&pool->pool_lock); applog(LOG_DEBUG, "Generated stratum coinbase %s", coinbase); @@ -4325,6 +4327,13 @@ static void gen_stratum_work(struct pool *pool, struct work *work) applog(LOG_DEBUG, "Generated stratum header %s", header); free(merkle_hash); + + if (!hex2bin(work->data, header, 128)) + quit(1, "Failed to convert header to data in gen_stratum_work"); + calc_midstate(work); + sprintf(hash1, "00000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000010000"); + if (!hex2bin(work->hash1, hash1, 64)) + quit(1, "Failed to convert hash1 in gen_stratum_work"); } static void get_work(struct work *work, struct thr_info *thr, const int thr_id) From 636f4b14d7f07eba8550908225139f22b9d96eb7 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 29 Sep 2012 11:38:52 +1000 Subject: [PATCH 033/160] Generate the work target in gen_stratum_work, setting default diff to 1 in case it is not yet set. --- cgminer.c | 17 +++++++++++++++-- util.c | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index 58e5177d..127bcc57 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4276,9 +4276,10 @@ static void gen_hash(unsigned char *data, unsigned char *hash, int len) static void gen_stratum_work(struct pool *pool, struct work *work) { unsigned char merkle_root[32], merkle_sha[64], *merkle_hash; - char header[256], hash1[128], *coinbase, *nonce2; + char header[256], hash1[128], *coinbase, *nonce2, *buf; uint32_t *data32, *swap32; - int len, i, diff; + uint64_t diff, diff64; + int len, i; mutex_lock(&pool->pool_lock); @@ -4328,12 +4329,24 @@ static void gen_stratum_work(struct pool *pool, struct work *work) free(merkle_hash); + /* Convert hex data to binary data for work */ if (!hex2bin(work->data, header, 128)) quit(1, "Failed to convert header to data in gen_stratum_work"); calc_midstate(work); sprintf(hash1, "00000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000010000"); if (!hex2bin(work->hash1, hash1, 64)) quit(1, "Failed to convert hash1 in gen_stratum_work"); + + /* Generate target as hex where 0x00000000FFFFFFFF is diff 1 */ + diff64 = 0x00000000FFFFFFFFULL * diff; + diff64 = ~htobe64(diff64); + sprintf((char *)work->target, "ffffffffffffffffffffffffffffffffffffffffffffffff"); + buf = bin2hex((const unsigned char *)&diff64, 8); + if (!buf) + quit(1, "Failed to convert diff64 to buf in gen_stratum_work"); + strcat((char *)work->target, buf); + free(buf); + applog(LOG_DEBUG, "Generated target %s", work->target); } static void get_work(struct work *work, struct thr_info *thr, const int thr_id) diff --git a/util.c b/util.c index 0c75bb57..a2e71519 100644 --- a/util.c +++ b/util.c @@ -1255,6 +1255,7 @@ out: if (ret) { pool->stratum_active = true; + pool->swork.diff = 1; if (opt_protocol) { applog(LOG_DEBUG, "Pool %d confirmed mining.notify with subscription %s extranonce1 %s extran2size %d", pool->pool_no, pool->subscription, pool->nonce1, pool->n2size); From 3db6fb4face0134e36215eab3e4ce64823af6c4b Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 29 Sep 2012 13:07:00 +1000 Subject: [PATCH 034/160] Create machinery to divert work requests to stratum. --- cgminer.c | 81 +++++++++++++++++++++++++++++++++++++------------------ miner.h | 2 ++ 2 files changed, 57 insertions(+), 26 deletions(-) diff --git a/cgminer.c b/cgminer.c index 127bcc57..b800ffec 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2069,19 +2069,22 @@ static double DIFFEXACTONE = 269599466671506397946670150870196306736371444225405 /* * Calculate the work share difficulty */ -static void calc_diff(struct work *work) +static void calc_diff(struct work *work, int known) { struct cgminer_pool_stats *pool_stats = &(work->pool->cgminer_pool_stats); double targ; int i; - targ = 0; - for (i = 31; i >= 0; i--) { - targ *= 256; - targ += work->target[i]; - } + if (!known) { + targ = 0; + for (i = 31; i >= 0; i--) { + targ *= 256; + targ += work->target[i]; + } - work->work_difficulty = DIFFEXACTONE / (targ ? : DIFFEXACTONE); + work->work_difficulty = DIFFEXACTONE / (targ ? : DIFFEXACTONE); + } else + work->work_difficulty = known; pool_stats->last_diff = work->work_difficulty; @@ -2115,7 +2118,7 @@ static void get_benchmark_work(struct work *work) gettimeofday(&(work->tv_getwork), NULL); memcpy(&(work->tv_getwork_reply), &(work->tv_getwork), sizeof(struct timeval)); work->getwork_mode = GETWORK_MODE_BENCHMARK; - calc_diff(work); + calc_diff(work, 0); } static bool get_upstream_work(struct work *work, CURL *curl) @@ -2163,7 +2166,7 @@ static bool get_upstream_work(struct work *work, CURL *curl) work->pool = pool; work->longpoll = false; work->getwork_mode = GETWORK_MODE_POOL; - calc_diff(work); + calc_diff(work, 0); total_getworks++; pool->getwork_requested++; @@ -2443,7 +2446,7 @@ static inline bool should_roll(struct work *work) * reject blocks as invalid. */ static inline bool can_roll(struct work *work) { - return (work->pool && work->rolltime && !work->clone && + return (!work->stratum && work->pool && work->rolltime && !work->clone && work->rolls < 7000 && !stale_work(work, false)); } @@ -2526,6 +2529,8 @@ static void pool_died(struct pool *pool) } } +static void gen_stratum_work(struct pool *pool, struct work *work); + static void *get_work_thread(void *userdata) { struct workio_cmd *wc = (struct workio_cmd *)userdata; @@ -2539,6 +2544,17 @@ static void *get_work_thread(void *userdata) pool = wc->pool; + if (pool->has_stratum) { + ret_work = make_work(); + gen_stratum_work(pool, ret_work); + if (unlikely(!stage_work(ret_work))) { + applog(LOG_ERR, "Failed to stage stratum work in get_work_thread"); + kill_work(); + free(ret_work); + } + goto out; + } + if (clone_available()) { dec_queued(pool); goto out; @@ -3014,15 +3030,17 @@ static void test_work_current(struct work *work) work_block++; - if (work->longpoll) { - applog(LOG_NOTICE, "LONGPOLL from pool %d detected new block", - work->pool->pool_no); - work->longpoll = false; - } else if (have_longpoll) - applog(LOG_NOTICE, "New block detected on network before longpoll"); - else - applog(LOG_NOTICE, "New block detected on network"); - restart_threads(); + if (!work->stratum) { + if (work->longpoll) { + applog(LOG_NOTICE, "LONGPOLL from pool %d detected new block", + work->pool->pool_no); + work->longpoll = false; + } else if (have_longpoll) + applog(LOG_NOTICE, "New block detected on network before longpoll"); + else + applog(LOG_NOTICE, "New block detected on network"); + restart_threads(); + } } else if (work->longpoll) { work->longpoll = false; if (work->pool == current_pool()) { @@ -4064,7 +4082,7 @@ static bool pool_active(struct pool *pool, bool pinging) memcpy(&(work->tv_getwork), &tv_getwork, sizeof(struct timeval)); memcpy(&(work->tv_getwork_reply), &tv_getwork_reply, sizeof(struct timeval)); work->getwork_mode = GETWORK_MODE_TESTPOOL; - calc_diff(work); + calc_diff(work, 0); applog(LOG_DEBUG, "Pushing pooltest work to base pool"); tq_push(thr_info[stage_thr_id].q, work); @@ -4220,6 +4238,12 @@ static struct work *hash_pop(const struct timespec *abstime) static bool reuse_work(struct work *work) { + if (work->stratum && !work->pool->idle) { + applog(LOG_DEBUG, "Reusing stratum work"); + gen_stratum_work(work->pool, work);; + return true; + } + if (can_roll(work) && should_roll(work)) { roll_work(work); return true; @@ -4347,6 +4371,16 @@ static void gen_stratum_work(struct pool *pool, struct work *work) strcat((char *)work->target, buf); free(buf); applog(LOG_DEBUG, "Generated target %s", work->target); + + work->pool = pool; + work->stratum = true; + work->blk.nonce = 0; + work->id = total_work++; + work->longpoll = false; + work->getwork_mode = GETWORK_MODE_STRATUM; + calc_diff(work, diff); + + gettimeofday(&work->tv_staged, NULL); } static void get_work(struct work *work, struct thr_info *thr, const int thr_id) @@ -4368,11 +4402,6 @@ static void get_work(struct work *work, struct thr_info *thr, const int thr_id) retry: pool = current_pool(); - if (pool->has_stratum) { - gen_stratum_work(pool, work); - goto out; - } - if (reuse_work(work)) goto out; @@ -4769,7 +4798,7 @@ static void convert_to_work(json_t *val, int rolltime, struct pool *pool, struct 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); + calc_diff(work, 0); if (pool->enabled == POOL_REJECTING) work->mandatory = true; diff --git a/miner.h b/miner.h index 28d102af..fe617fca 100644 --- a/miner.h +++ b/miner.h @@ -850,6 +850,7 @@ struct pool { #define GETWORK_MODE_POOL 'P' #define GETWORK_MODE_LP 'L' #define GETWORK_MODE_BENCHMARK 'B' +#define GETWORK_MODE_STRATUM 'S' struct work { unsigned char data[128]; @@ -878,6 +879,7 @@ struct work { bool mandatory; bool block; bool queued; + bool stratum; unsigned int work_block; int id; From ac47f7f3a6d52d5a3e1d161a487166560b927d32 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 29 Sep 2012 14:16:16 +1000 Subject: [PATCH 035/160] Store and display stripped url in its own variable. --- cgminer.c | 3 ++- miner.h | 1 + util.c | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index b800ffec..36bd6314 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4154,7 +4154,8 @@ static inline int cp_prio(void) static void pool_resus(struct pool *pool) { - applog(LOG_WARNING, "Pool %d %s alive", pool->pool_no, pool->rpc_url); + applog(LOG_WARNING, "Pool %d %s alive", pool->pool_no, + pool->has_stratum ? pool->stratum_url : pool->rpc_url); if (pool->prio < cp_prio() && pool_strategy == POOL_FAILOVER) switch_pools(NULL); } diff --git a/miner.h b/miner.h index fe617fca..7a1df40d 100644 --- a/miner.h +++ b/miner.h @@ -833,6 +833,7 @@ struct pool { struct cgminer_pool_stats cgminer_pool_stats; /* Stratum variables */ + char *stratum_url; SOCKETTYPE sock; struct sockaddr_in *server, client; char *subscription; diff --git a/util.c b/util.c index a2e71519..0c4b7368 100644 --- a/util.c +++ b/util.c @@ -843,6 +843,7 @@ bool extract_sockaddr(struct pool *pool, char *url) } pool->server = (struct sockaddr_in *)res->ai_addr; + pool->stratum_url = strdup(url_address); return true; } From 73d61ca4c384e378695ade71f5b12ba5b72094b0 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 29 Sep 2012 14:25:21 +1000 Subject: [PATCH 036/160] Fix work->target being a 32 byte binary in gen_stratum_work. --- cgminer.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cgminer.c b/cgminer.c index 36bd6314..6b43ae8f 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4304,6 +4304,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work) char header[256], hash1[128], *coinbase, *nonce2, *buf; uint32_t *data32, *swap32; uint64_t diff, diff64; + char target[64]; int len, i; mutex_lock(&pool->pool_lock); @@ -4365,13 +4366,15 @@ static void gen_stratum_work(struct pool *pool, struct work *work) /* Generate target as hex where 0x00000000FFFFFFFF is diff 1 */ diff64 = 0x00000000FFFFFFFFULL * diff; diff64 = ~htobe64(diff64); - sprintf((char *)work->target, "ffffffffffffffffffffffffffffffffffffffffffffffff"); + sprintf(target, "ffffffffffffffffffffffffffffffffffffffffffffffff"); buf = bin2hex((const unsigned char *)&diff64, 8); if (!buf) quit(1, "Failed to convert diff64 to buf in gen_stratum_work"); - strcat((char *)work->target, buf); + strcat(target, buf); free(buf); - applog(LOG_DEBUG, "Generated target %s", work->target); + applog(LOG_DEBUG, "Generated target %s", target); + if (!hex2bin(work->target, target, 32)) + quit(1, "Failed to convert target to bin in gen_stratum_work"); work->pool = pool; work->stratum = true; From 4a2975948048f643bbcfd6e2741b0973cab141a2 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 29 Sep 2012 14:48:34 +1000 Subject: [PATCH 037/160] Set lagging flag on first adding a pool to prevent pool slow warning at startup. --- cgminer.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 6b43ae8f..eaaba84c 100644 --- a/cgminer.c +++ b/cgminer.c @@ -5383,9 +5383,13 @@ void add_pool_details(struct pool *pool, bool live, char *url, char *user, char quit(1, "Failed to malloc userpass"); sprintf(pool->rpc_userpass, "%s:%s", pool->rpc_user, pool->rpc_pass); + enable_pool(pool); + + /* Prevent noise on startup */ + pool->lagging = true; + /* Test the pool is not idle if we're live running, otherwise * it will be tested separately */ - enable_pool(pool); if (live && !pool_active(pool, false)) pool->idle = true; } From aa93fa336c2cfda2817a21c87a4756c04196c22c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 29 Sep 2012 15:02:23 +1000 Subject: [PATCH 038/160] Copy parameters from stratum work required for share submission. --- cgminer.c | 6 +++++- miner.h | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index eaaba84c..645414bf 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4320,7 +4320,6 @@ static void gen_stratum_work(struct pool *pool, struct work *work) nonce2 = bin2hex((const unsigned char *)&pool->nonce2, pool->n2size); pool->nonce2++; strcat(coinbase, nonce2); - free(nonce2); strcat(coinbase, pool->swork.coinbase2); /* Generate merkle root */ @@ -4347,6 +4346,11 @@ static void gen_stratum_work(struct pool *pool, struct work *work) diff = pool->swork.diff; + /* Copy parameters required for share submission */ + work->job_id = strdup(pool->swork.job_id); + work->nonce2 = nonce2; + work->ntime = pool->swork.ntime; + mutex_unlock(&pool->pool_lock); applog(LOG_DEBUG, "Generated stratum coinbase %s", coinbase); diff --git a/miner.h b/miner.h index 7a1df40d..c220b9c8 100644 --- a/miner.h +++ b/miner.h @@ -880,7 +880,11 @@ struct work { bool mandatory; bool block; bool queued; + bool stratum; + char *job_id; + char *nonce2; + char *ntime; unsigned int work_block; int id; From 13fdff6531a6586dadebff913d85252577fb5bb7 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 29 Sep 2012 15:13:18 +1000 Subject: [PATCH 039/160] Free stratum buffers added to the work struct when freeing work ram. --- cgminer.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cgminer.c b/cgminer.c index 645414bf..285cd53c 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2190,6 +2190,11 @@ static struct work *make_work(void) static void free_work(struct work *work) { + if (work->stratum) { + free(work->job_id); + free(work->nonce2); + free(work->ntime); + } free(work); } From 7415d7aaa0b3a08b4863886adcfe209c102faed4 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 29 Sep 2012 16:10:13 +1000 Subject: [PATCH 040/160] Begin implementing a hash database of submissions and attempt sending results. --- cgminer.c | 39 +++++++++++++++++++++++++++++++++++++++ miner.h | 4 +--- util.c | 6 +++--- util.h | 1 + 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/cgminer.c b/cgminer.c index 285cd53c..55a2ca01 100644 --- a/cgminer.c +++ b/cgminer.c @@ -170,6 +170,7 @@ static pthread_mutex_t *stgd_lock; pthread_mutex_t console_lock; pthread_mutex_t ch_lock; static pthread_rwlock_t blk_lock; +static pthread_mutex_t sshare_lock; pthread_rwlock_t netacc_lock; @@ -225,6 +226,21 @@ struct block { static struct block *blocks = NULL; + +int swork_id; + +/* For creating a hash database of stratum shares submitted that have not had + * a response yet */ +struct stratum_share { + struct pool *pool; + char hash6[8]; + UT_hash_handle hh; + bool block; + int id; +}; + +static struct stratum_share *stratum_shares = NULL; + char *opt_socks_proxy = NULL; static const char def_conf[] = "cgminer.conf"; @@ -2712,6 +2728,28 @@ static void *submit_work_thread(void *userdata) work->stale = true; } + if (work->stratum) { + struct stratum_share *sshare = calloc(sizeof(struct stratum_share), 1); + uint32_t *hash32 = (uint32_t *)work->hash; + char *s = alloca(1024); + + sprintf(sshare->hash6, "%08lx", (unsigned long)hash32[6]); + sshare->block = work->block; + sshare->pool = pool; + /* Give the stratum share a unique id */ + mutex_lock(&sshare_lock); + sshare->id = swork_id++; + HASH_ADD_INT(stratum_shares, id, sshare); + mutex_unlock(&sshare_lock); + + sprintf(s, "{\"params\": [\"%s\", \"%s\", \"%s\", \"%s\", \"%08lx\"], \"id\": %d, \"method\": \"mining.submit\"}", + pool->rpc_user, work->job_id, work->nonce2, work->ntime, (unsigned long)work->blk.nonce, sshare->id); + + sock_send(pool->sock, s, strlen(s)); + + goto out; + } + ce = pop_curl_entry(pool); /* submit solution to bitcoin via JSON-RPC */ while (!submit_upstream_work(work, ce->curl, resubmit)) { @@ -5650,6 +5688,7 @@ int main(int argc, char *argv[]) mutex_init(&control_lock); mutex_init(&sharelog_lock); mutex_init(&ch_lock); + mutex_init(&sshare_lock); rwlock_init(&blk_lock); rwlock_init(&netacc_lock); diff --git a/miner.h b/miner.h index c220b9c8..e216be6a 100644 --- a/miner.h +++ b/miner.h @@ -595,6 +595,7 @@ extern bool opt_worktime; #ifdef USE_BITFORCE extern bool opt_bfl_noncerange; #endif +extern int swork_id; extern pthread_rwlock_t netacc_lock; @@ -752,9 +753,6 @@ enum pool_enable { }; struct stratum_work { - /* id we sent to receive this work */ - int id; - char *job_id; char *prev_hash; char *coinbase1; diff --git a/util.c b/util.c index 0c4b7368..b5888ea4 100644 --- a/util.c +++ b/util.c @@ -848,7 +848,7 @@ bool extract_sockaddr(struct pool *pool, char *url) } /* Send a single command across a socket, appending \n to it */ -static bool sock_send(int sock, char *s, ssize_t len) +bool sock_send(int sock, char *s, ssize_t len) { ssize_t sent = 0; @@ -1115,7 +1115,7 @@ bool auth_stratum(struct pool *pool) s = alloca(RECVSIZE); sprintf(s, "{\"id\": %d, \"method\": \"mining.authorize\", \"params\": [\"%s\", \"%s\"]}", - pool->swork.id++, pool->rpc_user, pool->rpc_pass); + swork_id++, pool->rpc_user, pool->rpc_pass); /* Parse all data prior sending auth request */ while (sock_full(pool->sock, false)) { @@ -1171,7 +1171,7 @@ bool initiate_stratum(struct pool *pool) bool ret = false; s = alloca(RECVSIZE); - sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": []}", pool->swork.id++); + sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": []}", swork_id++); pool->sock = socket(AF_INET, SOCK_STREAM, 0); if (pool->sock == INVSOCK) diff --git a/util.h b/util.h index 4eb51a70..2746e101 100644 --- a/util.h +++ b/util.h @@ -109,6 +109,7 @@ #endif #endif struct pool; +bool sock_send(int sock, char *s, ssize_t len); char *recv_line(SOCKETTYPE sock); bool parse_stratum(struct pool *pool, char *s); bool extract_sockaddr(struct pool *pool, char *url); From fab9ff3cb7c4120baebf64756528293d4a1117d2 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 29 Sep 2012 16:10:44 +1000 Subject: [PATCH 041/160] Revert "Free stratum buffers added to the work struct when freeing work ram." This reverts commit 13fdff6531a6586dadebff913d85252577fb5bb7. Not always allocated... needs some more thought. --- cgminer.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/cgminer.c b/cgminer.c index 55a2ca01..8d62c96f 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2206,11 +2206,6 @@ static struct work *make_work(void) static void free_work(struct work *work) { - if (work->stratum) { - free(work->job_id); - free(work->nonce2); - free(work->ntime); - } free(work); } From aa6aa29c4d723367a9eca7f02c4d8f6d182e6672 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 29 Sep 2012 17:06:48 +1000 Subject: [PATCH 042/160] Check that stratum is already active in initiate_stratum to avoid de-authorising ourselves by subscribing again. --- util.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/util.c b/util.c index b5888ea4..d31167e1 100644 --- a/util.c +++ b/util.c @@ -1170,6 +1170,9 @@ bool initiate_stratum(struct pool *pool) json_error_t err; bool ret = false; + if (pool->stratum_active) + return true; + s = alloca(RECVSIZE); sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": []}", swork_id++); From 61360952f542115d085c362e8a68d86ceda41e6e Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 29 Sep 2012 17:44:19 +1000 Subject: [PATCH 043/160] Fix endianness of nonce submitted for stratum. --- cgminer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 8d62c96f..529f9fb2 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2738,7 +2738,7 @@ static void *submit_work_thread(void *userdata) mutex_unlock(&sshare_lock); sprintf(s, "{\"params\": [\"%s\", \"%s\", \"%s\", \"%s\", \"%08lx\"], \"id\": %d, \"method\": \"mining.submit\"}", - pool->rpc_user, work->job_id, work->nonce2, work->ntime, (unsigned long)work->blk.nonce, sshare->id); + pool->rpc_user, work->job_id, work->nonce2, work->ntime, (unsigned long)htobe32(work->blk.nonce), sshare->id); sock_send(pool->sock, s, strlen(s)); From fb987fd25a3ff7a7eb3d462c0504559a54e9d0b9 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 29 Sep 2012 19:15:58 +1000 Subject: [PATCH 044/160] We should be hashing the binary coinbase, not the hex one. --- cgminer.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/cgminer.c b/cgminer.c index 529f9fb2..f0d2e0ee 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4338,33 +4338,36 @@ static void gen_hash(unsigned char *data, unsigned char *hash, int len) static void gen_stratum_work(struct pool *pool, struct work *work) { - unsigned char merkle_root[32], merkle_sha[64], *merkle_hash; - char header[256], hash1[128], *coinbase, *nonce2, *buf; + char header[256], hash1[128], *nonce2, *buf; + unsigned char *coinbase, merkle_root[32], merkle_sha[64], *merkle_hash; uint32_t *data32, *swap32; uint64_t diff, diff64; char target[64]; - int len, i; + int len, cb1_len, n1_len, cb2_len, i; mutex_lock(&pool->pool_lock); /* Generate coinbase */ - len = strlen(pool->swork.coinbase1) + - strlen(pool->nonce1) + - pool->n2size + - strlen(pool->swork.coinbase2); - coinbase = alloca(len + 1); - sprintf(coinbase, "%s", pool->swork.coinbase1); - strcat(coinbase, pool->nonce1); nonce2 = bin2hex((const unsigned char *)&pool->nonce2, pool->n2size); pool->nonce2++; - strcat(coinbase, nonce2); - strcat(coinbase, pool->swork.coinbase2); + cb1_len = strlen(pool->swork.coinbase1) / 2; + n1_len = strlen(pool->nonce1) / 2; + cb2_len = strlen(pool->swork.coinbase2) / 2; + len = cb1_len + n1_len + pool->n2size + cb2_len; + coinbase = alloca(len); + hex2bin(coinbase, pool->swork.coinbase1, cb1_len); + hex2bin(coinbase + cb1_len, pool->nonce1, n1_len); + hex2bin(coinbase + cb1_len + n1_len, pool->swork.coinbase2, cb2_len); + hex2bin(coinbase + cb1_len + n1_len + cb2_len, nonce2, pool->n2size); /* Generate merkle root */ - gen_hash((unsigned char *)coinbase, merkle_root, len); + gen_hash(coinbase, merkle_root, len); memcpy(merkle_sha, merkle_root, 32); for (i = 0; i < pool->swork.merkles; i++) { - memcpy(merkle_sha + 32, pool->swork.merkle[i], 32); + unsigned char merkle_bin[32]; + + hex2bin(merkle_bin, pool->swork.merkle[i], 32); + memcpy(merkle_sha + 32, merkle_bin, 32); gen_hash(merkle_sha, merkle_root, 64); memcpy(merkle_sha, merkle_root, 32); } @@ -4391,7 +4394,6 @@ static void gen_stratum_work(struct pool *pool, struct work *work) mutex_unlock(&pool->pool_lock); - applog(LOG_DEBUG, "Generated stratum coinbase %s", coinbase); applog(LOG_DEBUG, "Generated stratum merkle %s", merkle_hash); applog(LOG_DEBUG, "Generated stratum header %s", header); From 41acd23d0fa82af7000890367d299571f8e476bb Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 29 Sep 2012 23:59:55 +1000 Subject: [PATCH 045/160] Extranonce2 should be added before coinbase2. --- cgminer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index f0d2e0ee..fd61053d 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4357,8 +4357,8 @@ static void gen_stratum_work(struct pool *pool, struct work *work) coinbase = alloca(len); hex2bin(coinbase, pool->swork.coinbase1, cb1_len); hex2bin(coinbase + cb1_len, pool->nonce1, n1_len); - hex2bin(coinbase + cb1_len + n1_len, pool->swork.coinbase2, cb2_len); - hex2bin(coinbase + cb1_len + n1_len + cb2_len, nonce2, pool->n2size); + hex2bin(coinbase + cb1_len + n1_len, nonce2, pool->n2size); + hex2bin(coinbase + cb1_len + n1_len + pool->n2size, pool->swork.coinbase2, cb2_len); /* Generate merkle root */ gen_hash(coinbase, merkle_root, len); From 6593b8932822bf93bb300db218ed9d656496a8d7 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 30 Sep 2012 16:47:06 +1000 Subject: [PATCH 046/160] Correct nonce submitted with share. --- cgminer.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cgminer.c b/cgminer.c index fd61053d..0cfa1c49 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2725,8 +2725,9 @@ static void *submit_work_thread(void *userdata) if (work->stratum) { struct stratum_share *sshare = calloc(sizeof(struct stratum_share), 1); - uint32_t *hash32 = (uint32_t *)work->hash; + uint32_t *hash32 = (uint32_t *)work->hash, nonce; char *s = alloca(1024); + char *noncehex; sprintf(sshare->hash6, "%08lx", (unsigned long)hash32[6]); sshare->block = work->block; @@ -2737,8 +2738,12 @@ static void *submit_work_thread(void *userdata) HASH_ADD_INT(stratum_shares, id, sshare); mutex_unlock(&sshare_lock); - sprintf(s, "{\"params\": [\"%s\", \"%s\", \"%s\", \"%s\", \"%08lx\"], \"id\": %d, \"method\": \"mining.submit\"}", - pool->rpc_user, work->job_id, work->nonce2, work->ntime, (unsigned long)htobe32(work->blk.nonce), sshare->id); + nonce = *((uint32_t *)(work->data + 76)); + noncehex = bin2hex((const unsigned char *)&nonce, 4); + + sprintf(s, "{\"params\": [\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"], \"id\": %d, \"method\": \"mining.submit\"}", + pool->rpc_user, work->job_id, work->nonce2, work->ntime, noncehex, sshare->id); + free(noncehex); sock_send(pool->sock, s, strlen(s)); From aaaa8a52fdc6ee0b7b894cfc0a417502d60dedbc Mon Sep 17 00:00:00 2001 From: Kano Date: Sun, 30 Sep 2012 17:37:01 +1000 Subject: [PATCH 047/160] Icarus catch more USB errors and close/reopen the port --- driver-icarus.c | 67 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 14 deletions(-) diff --git a/driver-icarus.c b/driver-icarus.c index 4214c31b..cc74df2a 100644 --- a/driver-icarus.c +++ b/driver-icarus.c @@ -223,6 +223,11 @@ static void rev(unsigned char *s, size_t l) #define icarus_open2(devpath, baud, purge) serial_open(devpath, baud, ICARUS_READ_FAULT_DECISECONDS, purge) #define icarus_open(devpath, baud) icarus_open2(devpath, baud, false) +#define ICA_GETS_ERROR -1 +#define ICA_GETS_OK 0 +#define ICA_GETS_RESTART 1 +#define ICA_GETS_TIMEOUT 2 + static int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, struct thr_info *thr, int read_count) { ssize_t ret = 0; @@ -233,12 +238,14 @@ static int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, st // Read reply 1 byte at a time to get earliest tv_finish while (true) { ret = read(fd, buf, 1); + if (ret < 0) + return ICA_GETS_ERROR; if (first) gettimeofday(tv_finish, NULL); if (ret >= read_amount) - return 0; + return ICA_GETS_OK; if (ret > 0) { buf += ret; @@ -254,16 +261,16 @@ static int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, st "Icarus Read: No data in %.2f seconds", (float)rc/(float)TIME_FACTOR); } - return 1; + return ICA_GETS_TIMEOUT; } - if (thr->work_restart) { + if (thr && thr->work_restart) { if (opt_debug) { applog(LOG_DEBUG, "Icarus Read: Work restart at %.2f seconds", (float)(rc)/(float)TIME_FACTOR); } - return 1; + return ICA_GETS_RESTART; } } } @@ -281,6 +288,13 @@ static int icarus_write(int fd, const void *buf, size_t bufLen) #define icarus_close(fd) close(fd) +static void do_icarus_close(struct thr_info *thr) +{ + struct cgpu_info *icarus = thr->cgpu; + icarus_close(icarus->device_fd); + icarus->device_fd = -1; +} + static const char *timing_mode_str(enum timing_mode timing_mode) { switch(timing_mode) { @@ -533,10 +547,7 @@ static bool icarus_detect_one(const char *devpath) gettimeofday(&tv_start, NULL); memset(nonce_bin, 0, sizeof(nonce_bin)); - struct thr_info dummy = { - .work_restart = false, - }; - icarus_gets(nonce_bin, fd, &tv_finish, &dummy, 1); + icarus_gets(nonce_bin, fd, &tv_finish, NULL, 1); icarus_close(fd); @@ -563,6 +574,7 @@ static bool icarus_detect_one(const char *devpath) icarus = calloc(1, sizeof(struct cgpu_info)); icarus->api = &icarus_api; icarus->device_path = strdup(devpath); + icarus->device_fd = -1; icarus->threads = 1; add_cgpu(icarus); icarus_info = realloc(icarus_info, sizeof(struct ICARUS_INFO *) * (total_devices + 1)); @@ -607,6 +619,8 @@ static bool icarus_prepare(struct thr_info *thr) struct timeval now; + icarus->device_fd = -1; + int fd = icarus_open(icarus->device_path, icarus_info[icarus->device_id]->baud); if (unlikely(-1 == fd)) { applog(LOG_ERR, "Failed to open Icarus on %s", @@ -653,6 +667,17 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, elapsed.tv_sec = elapsed.tv_usec = 0; icarus = thr->cgpu; + if (icarus->device_fd == -1) + if (!icarus_prepare(thr)) { + applog(LOG_ERR, "ICA%i: Comms error", icarus->device_id); + icarus->device_last_not_well = time(NULL); + icarus->device_not_well_reason = REASON_DEV_COMMS_ERROR; + icarus->dev_comms_error_count++; + + // fail the device if the reopen attempt fails + return -1; + } + fd = icarus->device_fd; memset(ob_bin, 0, sizeof(ob_bin)); @@ -664,8 +689,10 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, tcflush(fd, TCOFLUSH); #endif ret = icarus_write(fd, ob_bin, sizeof(ob_bin)); - if (ret) - return -1; /* This should never happen */ + if (ret) { + do_icarus_close(thr); + return 0; /* This should never happen */ + } gettimeofday(&tv_start, NULL); @@ -682,12 +709,19 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, memset(nonce_bin, 0, sizeof(nonce_bin)); info = icarus_info[icarus->device_id]; ret = icarus_gets(nonce_bin, fd, &tv_finish, thr, info->read_count); + if (ret == ICA_GETS_ERROR) { + do_icarus_close(thr); + applog(LOG_ERR, "ICA%i: Comms error", icarus->device_id); + icarus->device_last_not_well = time(NULL); + icarus->device_not_well_reason = REASON_DEV_COMMS_ERROR; + icarus->dev_comms_error_count++; + return 0; + } work->blk.nonce = 0xffffffff; - memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin)); // aborted before becoming idle, get new work - if (nonce == 0 && ret) { + if (ret == ICA_GETS_TIMEOUT || ret == ICA_GETS_RESTART) { timersub(&tv_finish, &tv_start, &elapsed); // ONLY up to just when it aborted @@ -709,6 +743,8 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, return estimate_hashes; } + memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin)); + #if !defined (__BIG_ENDIAN__) && !defined(MIPSEB) nonce = swab32(nonce); #endif @@ -717,6 +753,10 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, submit_nonce(thr, work, nonce); was_hw_error = (curr_hw_errors > icarus->hw_errors); + // Force a USB close/reopen on any hw error + if (was_hw_error) + do_icarus_close(thr); + hash_count = (nonce & info->nonce_mask); hash_count++; hash_count *= info->fpga_count; @@ -862,8 +902,7 @@ static struct api_data *icarus_api_stats(struct cgpu_info *cgpu) static void icarus_shutdown(struct thr_info *thr) { - struct cgpu_info *icarus = thr->cgpu; - icarus_close(icarus->device_fd); + do_icarus_close(thr); } struct device_api icarus_api = { From 6d6692ce9ae8dfbcdde8a3a8560bbfb35a9e450e Mon Sep 17 00:00:00 2001 From: Kano Date: Sun, 30 Sep 2012 17:38:27 +1000 Subject: [PATCH 048/160] api.c DEBUG message has no paramter --- api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api.c b/api.c index 8ebf94da..1b22087c 100644 --- a/api.c +++ b/api.c @@ -558,7 +558,7 @@ struct CODES { { SEVERITY_ERR, MSG_INVBOOL, PARAM_NONE, "Invalid parameter should be true or false" }, { SEVERITY_SUCC, MSG_FOO, PARAM_BOOL, "Failover-Only set to %s" }, { SEVERITY_SUCC, MSG_MINECOIN,PARAM_NONE, "CGMiner coin" }, - { SEVERITY_SUCC, MSG_DEBUGSET,PARAM_STR, "Debug settings" }, + { SEVERITY_SUCC, MSG_DEBUGSET,PARAM_NONE, "Debug settings" }, #ifdef HAVE_AN_FPGA { SEVERITY_SUCC, MSG_PGAIDENT,PARAM_PGA, "Identify command sent to PGA%d" }, { SEVERITY_WARN, MSG_PGANOID, PARAM_PGA, "PGA%d does not support identify" }, From c2b1504e505882a94487ce01b7eac714599191ed Mon Sep 17 00:00:00 2001 From: Kano Date: Sun, 30 Sep 2012 17:44:36 +1000 Subject: [PATCH 049/160] Icarus USB write failure is also a comms error --- driver-icarus.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/driver-icarus.c b/driver-icarus.c index cc74df2a..b3aa34bd 100644 --- a/driver-icarus.c +++ b/driver-icarus.c @@ -691,6 +691,10 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, ret = icarus_write(fd, ob_bin, sizeof(ob_bin)); if (ret) { do_icarus_close(thr); + applog(LOG_ERR, "ICA%i: Comms error", icarus->device_id); + icarus->device_last_not_well = time(NULL); + icarus->device_not_well_reason = REASON_DEV_COMMS_ERROR; + icarus->dev_comms_error_count++; return 0; /* This should never happen */ } From 9180a557c3a089b229428878697f4369a17319cb Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 30 Sep 2012 19:11:22 +1000 Subject: [PATCH 050/160] Count each stratum notify as a getwork equivalent. --- util.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/util.c b/util.c index d31167e1..f6480c43 100644 --- a/util.c +++ b/util.c @@ -1032,6 +1032,9 @@ static bool parse_notify(struct pool *pool, json_t *val) applog(LOG_DEBUG, "clean: %s", clean ? "yes" : "no"); } + /* A notify message is the closest stratum gets to a getwork */ + pool->getwork_requested++; + total_getworks++; return true; } From b871f69f6226bb4fbd7c08517a26792b7635d1e6 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 30 Sep 2012 19:13:50 +1000 Subject: [PATCH 051/160] Display stratum as mechanism in status line when current pool is running it. --- cgminer.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index 0cfa1c49..d76549e4 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1522,12 +1522,16 @@ static void curses_print_status(void) global_queued(), total_staged(), total_stale, total_discarded, new_blocks, local_work, total_go, total_ro, total_diff1 / total_secs * 60); wclrtoeol(statuswin); - if ((pool_strategy == POOL_LOADBALANCE || pool_strategy == POOL_BALANCE) && total_pools > 1) + if (pool->has_stratum) { + mvwprintw(statuswin, 4, 0, " Connected to %s with stratum as user %s", + pool->stratum_url, pool->rpc_user); + } else if ((pool_strategy == POOL_LOADBALANCE || pool_strategy == POOL_BALANCE) && total_pools > 1) { mvwprintw(statuswin, 4, 0, " Connected to multiple pools with%s LP", have_longpoll ? "": "out"); - else + } else { mvwprintw(statuswin, 4, 0, " Connected to %s with%s LP as user %s", pool->rpc_url, have_longpoll ? "": "out", pool->rpc_user); + } wclrtoeol(statuswin); mvwprintw(statuswin, 5, 0, " Block: %s... Started: %s", current_hash, blocktime); mvwhline(statuswin, 6, 0, '-', 80); From 739cba28a7dfffe24d40a80df4072e78bd2409cf Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 30 Sep 2012 19:19:46 +1000 Subject: [PATCH 052/160] Rename parse_stratum to parse_method as it is only for stratum messages that contain methods. --- cgminer.c | 2 +- util.c | 4 ++-- util.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cgminer.c b/cgminer.c index d76549e4..a8932d55 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4055,7 +4055,7 @@ static void *stratum_thread(void *userdata) s = recv_line(pool->sock); if (unlikely(!s)) continue; - if (!parse_stratum(pool, s)) /* Create message queues here */ + if (!parse_method(pool, s)) /* Create message queues here */ applog(LOG_INFO, "Unknown stratum msg: %s", s); free(s); if (unlikely(pool->swork.clean)) { diff --git a/util.c b/util.c index f6480c43..d478abed 100644 --- a/util.c +++ b/util.c @@ -1055,7 +1055,7 @@ static bool parse_diff(struct pool *pool, json_t *val) return true; } -bool parse_stratum(struct pool *pool, char *s) +bool parse_method(struct pool *pool, char *s) { json_t *val = NULL, *method, *err_val, *params; json_error_t err; @@ -1123,7 +1123,7 @@ bool auth_stratum(struct pool *pool) /* Parse all data prior sending auth request */ while (sock_full(pool->sock, false)) { sret = recv_line(pool->sock); - if (!parse_stratum(pool, sret)) { + if (!parse_method(pool, sret)) { clear_sock(pool->sock); applog(LOG_WARNING, "Failed to parse stratum buffer"); free(sret); diff --git a/util.h b/util.h index 2746e101..ec9e8d0d 100644 --- a/util.h +++ b/util.h @@ -111,7 +111,7 @@ struct pool; bool sock_send(int sock, char *s, ssize_t len); char *recv_line(SOCKETTYPE sock); -bool parse_stratum(struct pool *pool, char *s); +bool parse_method(struct pool *pool, char *s); bool extract_sockaddr(struct pool *pool, char *url); bool auth_stratum(struct pool *pool); bool initiate_stratum(struct pool *pool); From 2de951518e44a5eea6eb1e0fd14f8ac48265cc66 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 30 Sep 2012 20:24:24 +1000 Subject: [PATCH 053/160] Abstract out share submit as a function to be useable by stratum. --- cgminer.c | 269 +++++++++++++++++++++++++++++++++--------------------- util.c | 7 +- util.h | 7 ++ 3 files changed, 172 insertions(+), 111 deletions(-) diff --git a/cgminer.c b/cgminer.c index a8932d55..4d6dd168 100644 --- a/cgminer.c +++ b/cgminer.c @@ -232,10 +232,9 @@ int swork_id; /* For creating a hash database of stratum shares submitted that have not had * a response yet */ struct stratum_share { - struct pool *pool; - char hash6[8]; UT_hash_handle hh; bool block; + struct work work; int id; }; @@ -1800,6 +1799,114 @@ static void reject_pool(struct pool *pool) pool->enabled = POOL_REJECTING; } +/* Theoretically threads could race when modifying accepted and + * rejected values but the chance of two submits completing at the + * same time is zero so there is no point adding extra locking */ +static void +share_result(json_t *val, json_t *res, const struct work *work, char *hashshow, + bool resubmit, char *worktime) +{ + struct pool *pool = work->pool; + struct cgpu_info *cgpu = thr_info[work->thr_id].cgpu; + + if (json_is_true(res)) { + cgpu->accepted++; + total_accepted++; + pool->accepted++; + cgpu->diff_accepted += work->work_difficulty; + total_diff_accepted += work->work_difficulty; + pool->diff_accepted += work->work_difficulty; + pool->seq_rejects = 0; + cgpu->last_share_pool = pool->pool_no; + cgpu->last_share_pool_time = time(NULL); + cgpu->last_share_diff = work->work_difficulty; + pool->last_share_time = cgpu->last_share_pool_time; + pool->last_share_diff = work->work_difficulty; + applog(LOG_DEBUG, "PROOF OF WORK RESULT: true (yay!!!)"); + if (!QUIET) { + if (total_pools > 1) + applog(LOG_NOTICE, "Accepted %s %s %d pool %d %s%s", + hashshow, cgpu->api->name, cgpu->device_id, work->pool->pool_no, resubmit ? "(resubmit)" : "", worktime); + else + applog(LOG_NOTICE, "Accepted %s %s %d %s%s", + hashshow, cgpu->api->name, cgpu->device_id, resubmit ? "(resubmit)" : "", worktime); + } + sharelog("accept", work); + if (opt_shares && total_accepted >= opt_shares) { + applog(LOG_WARNING, "Successfully mined %d accepted shares as requested and exiting.", opt_shares); + kill_work(); + return; + } + + /* Detect if a pool that has been temporarily disabled for + * continually rejecting shares has started accepting shares. + * This will only happen with the work returned from a + * longpoll */ + if (unlikely(pool->enabled == POOL_REJECTING)) { + applog(LOG_WARNING, "Rejecting pool %d now accepting shares, re-enabling!", pool->pool_no); + enable_pool(pool); + switch_pools(NULL); + } + } else { + cgpu->rejected++; + total_rejected++; + pool->rejected++; + cgpu->diff_rejected += work->work_difficulty; + total_diff_rejected += work->work_difficulty; + pool->diff_rejected += work->work_difficulty; + pool->seq_rejects++; + applog(LOG_DEBUG, "PROOF OF WORK RESULT: false (booooo)"); + if (!QUIET) { + char where[17]; + char disposition[36] = "reject"; + char reason[32]; + + if (total_pools > 1) + sprintf(where, "pool %d", work->pool->pool_no); + else + strcpy(where, ""); + + res = json_object_get(val, "reject-reason"); + if (res) { + const char *reasontmp = json_string_value(res); + + size_t reasonLen = strlen(reasontmp); + if (reasonLen > 28) + reasonLen = 28; + reason[0] = ' '; reason[1] = '('; + memcpy(2 + reason, reasontmp, reasonLen); + reason[reasonLen + 2] = ')'; reason[reasonLen + 3] = '\0'; + memcpy(disposition + 7, reasontmp, reasonLen); + disposition[6] = ':'; disposition[reasonLen + 7] = '\0'; + } else + strcpy(reason, ""); + + applog(LOG_NOTICE, "Rejected %s %s %d %s%s %s%s", + hashshow, cgpu->api->name, cgpu->device_id, where, reason, resubmit ? "(resubmit)" : "", worktime); + sharelog(disposition, work); + } + + /* Once we have more than a nominal amount of sequential rejects, + * at least 10 and more than 3 mins at the current utility, + * disable the pool because some pool error is likely to have + * ensued. Do not do this if we know the share just happened to + * be stale due to networking delays. + */ + if (pool->seq_rejects > 10 && !work->stale && opt_disable_pool && enabled_pools > 1) { + double utility = total_accepted / total_secs * 60; + + if (pool->seq_rejects > utility * 3) { + applog(LOG_WARNING, "Pool %d rejected %d sequential shares, disabling!", + pool->pool_no, pool->seq_rejects); + reject_pool(pool); + if (pool == current_pool()) + switch_pools(NULL); + pool->seq_rejects = 0; + } + } + } +} + static bool submit_upstream_work(const struct work *work, CURL *curl, bool resubmit) { char *hexstr = NULL; @@ -1908,105 +2015,7 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub } } - /* Theoretically threads could race when modifying accepted and - * rejected values but the chance of two submits completing at the - * same time is zero so there is no point adding extra locking */ - if (json_is_true(res)) { - cgpu->accepted++; - total_accepted++; - pool->accepted++; - cgpu->diff_accepted += work->work_difficulty; - total_diff_accepted += work->work_difficulty; - pool->diff_accepted += work->work_difficulty; - pool->seq_rejects = 0; - cgpu->last_share_pool = pool->pool_no; - cgpu->last_share_pool_time = time(NULL); - cgpu->last_share_diff = work->work_difficulty; - pool->last_share_time = cgpu->last_share_pool_time; - pool->last_share_diff = work->work_difficulty; - applog(LOG_DEBUG, "PROOF OF WORK RESULT: true (yay!!!)"); - if (!QUIET) { - if (total_pools > 1) - applog(LOG_NOTICE, "Accepted %s %s %d pool %d %s%s", - hashshow, cgpu->api->name, cgpu->device_id, work->pool->pool_no, resubmit ? "(resubmit)" : "", worktime); - else - applog(LOG_NOTICE, "Accepted %s %s %d %s%s", - hashshow, cgpu->api->name, cgpu->device_id, resubmit ? "(resubmit)" : "", worktime); - } - sharelog("accept", work); - if (opt_shares && total_accepted >= opt_shares) { - applog(LOG_WARNING, "Successfully mined %d accepted shares as requested and exiting.", opt_shares); - kill_work(); - goto out; - } - - /* Detect if a pool that has been temporarily disabled for - * continually rejecting shares has started accepting shares. - * This will only happen with the work returned from a - * longpoll */ - if (unlikely(pool->enabled == POOL_REJECTING)) { - applog(LOG_WARNING, "Rejecting pool %d now accepting shares, re-enabling!", pool->pool_no); - enable_pool(pool); - switch_pools(NULL); - } - } else { - cgpu->rejected++; - total_rejected++; - pool->rejected++; - cgpu->diff_rejected += work->work_difficulty; - total_diff_rejected += work->work_difficulty; - pool->diff_rejected += work->work_difficulty; - pool->seq_rejects++; - applog(LOG_DEBUG, "PROOF OF WORK RESULT: false (booooo)"); - if (!QUIET) { - char where[17]; - char disposition[36] = "reject"; - char reason[32]; - - if (total_pools > 1) - sprintf(where, "pool %d", work->pool->pool_no); - else - strcpy(where, ""); - - res = json_object_get(val, "reject-reason"); - if (res) { - const char *reasontmp = json_string_value(res); - - size_t reasonLen = strlen(reasontmp); - if (reasonLen > 28) - reasonLen = 28; - reason[0] = ' '; reason[1] = '('; - memcpy(2 + reason, reasontmp, reasonLen); - reason[reasonLen + 2] = ')'; reason[reasonLen + 3] = '\0'; - memcpy(disposition + 7, reasontmp, reasonLen); - disposition[6] = ':'; disposition[reasonLen + 7] = '\0'; - } else - strcpy(reason, ""); - - applog(LOG_NOTICE, "Rejected %s %s %d %s%s %s%s", - hashshow, cgpu->api->name, cgpu->device_id, where, reason, resubmit ? "(resubmit)" : "", worktime); - sharelog(disposition, work); - } - - /* Once we have more than a nominal amount of sequential rejects, - * at least 10 and more than 3 mins at the current utility, - * disable the pool because some pool error is likely to have - * ensued. Do not do this if we know the share just happened to - * be stale due to networking delays. - */ - if (pool->seq_rejects > 10 && !work->stale && opt_disable_pool && enabled_pools > 1) { - double utility = total_accepted / total_secs * 60; - - if (pool->seq_rejects > utility * 3) { - applog(LOG_WARNING, "Pool %d rejected %d sequential shares, disabling!", - pool->pool_no, pool->seq_rejects); - reject_pool(pool); - if (pool == current_pool()) - switch_pools(NULL); - pool->seq_rejects = 0; - } - } - } + share_result(val, res, work, hashshow, resubmit, worktime); cgpu->utility = cgpu->accepted / total_secs * 60; @@ -2733,9 +2742,8 @@ static void *submit_work_thread(void *userdata) char *s = alloca(1024); char *noncehex; - sprintf(sshare->hash6, "%08lx", (unsigned long)hash32[6]); - sshare->block = work->block; - sshare->pool = pool; + memcpy(&sshare->work, work, sizeof(struct work)); + /* Give the stratum share a unique id */ mutex_lock(&sshare_lock); sshare->id = swork_id++; @@ -4022,6 +4030,57 @@ out_unlock: } } +/* 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) +{ + json_t *val = NULL, *err_val, *res_val, *id_val; + struct stratum_share *sshare; + json_error_t err; + bool ret = false; + int id; + + val = JSON_LOADS(s, &err); + if (!val) { + applog(LOG_INFO, "JSON decode failed(%d): %s", err.line, err.text);; + goto out; + } + + res_val = json_object_get(val, "result"); + err_val = json_object_get(val, "error"); + id_val = json_object_get(val, "id"); + + if ((!res_val || !id_val) || (json_is_null(res_val) || json_is_null(id_val)) || + (err_val && !json_is_null(err_val))) { + char *ss; + + if (err_val) + ss = json_dumps(err_val, JSON_INDENT(3)); + else + ss = strdup("(unknown reason)"); + + applog(LOG_INFO, "JSON-RPC decode failed: %s", ss); + + free(ss); + + goto out; + } + + mutex_lock(&sshare_lock); + HASH_FIND_INT(stratum_shares, &id, sshare); + if (sshare) + HASH_DEL(stratum_shares, sshare); + mutex_unlock(&sshare_lock); + if (!sshare) + goto out; + ret = true; +out: + if (val) + json_decref(val); + + return ret; +} + /* 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 @@ -4055,7 +4114,7 @@ static void *stratum_thread(void *userdata) s = recv_line(pool->sock); if (unlikely(!s)) continue; - if (!parse_method(pool, s)) /* Create message queues here */ + if (!parse_method(pool, s) && !parse_stratum_response(s)) applog(LOG_INFO, "Unknown stratum msg: %s", s); free(s); if (unlikely(pool->swork.clean)) { diff --git a/util.c b/util.c index d478abed..dd933c50 100644 --- a/util.c +++ b/util.c @@ -35,12 +35,7 @@ #include "miner.h" #include "elist.h" #include "compat.h" - -#if JANSSON_MAJOR_VERSION >= 2 -#define JSON_LOADS(str, err_ptr) json_loads((str), 0, (err_ptr)) -#else -#define JSON_LOADS(str, err_ptr) json_loads((str), (err_ptr)) -#endif +#include "util.h" bool successful_connect = false; struct timeval nettime; diff --git a/util.h b/util.h index ec9e8d0d..51b87787 100644 --- a/util.h +++ b/util.h @@ -108,6 +108,13 @@ #define in_addr_t uint32_t #endif #endif + +#if JANSSON_MAJOR_VERSION >= 2 +#define JSON_LOADS(str, err_ptr) json_loads((str), 0, (err_ptr)) +#else +#define JSON_LOADS(str, err_ptr) json_loads((str), (err_ptr)) +#endif + struct pool; bool sock_send(int sock, char *s, ssize_t len); char *recv_line(SOCKETTYPE sock); From fa4c9bf60fa4628c627adea196141871203b1e99 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 30 Sep 2012 22:40:41 +1000 Subject: [PATCH 054/160] Use a more robust mechanism to obtain a \n terminated string over a socket. --- util.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/util.c b/util.c index dd933c50..542cbc48 100644 --- a/util.c +++ b/util.c @@ -895,8 +895,8 @@ static bool sock_full(SOCKETTYPE sock, bool wait) * from the socket and returns that as a malloced char */ char *recv_line(SOCKETTYPE sock) { - char *sret = NULL, *s; - ssize_t len; + char *sret = NULL, *s, c; + ssize_t offset = 0; s = alloca(RECVSIZE); if (SOCKETFAIL(recv(sock, s, RECVSIZE, MSG_PEEK))) { @@ -908,12 +908,13 @@ char *recv_line(SOCKETTYPE sock) applog(LOG_DEBUG, "Failed to parse a \\n terminated string in recv_line"); goto out; } - len = strlen(sret) + 1; - /* We know how much data is in the buffer so this read should not fail */ - if (SOCKETFAIL(recv(sock, s, len, 0))) - goto out; - if (s) - sret = strdup(strtok(s, "\n")); + + do { + read(sock, &c, 1); + memcpy(s + offset++, &c, 1); + } while (strncmp(&c, "\n", 1)); + sret = strdup(s); + strcpy(sret + offset - 1, "\0"); out: if (!sret) clear_sock(sock); From 8baac0d66d0059fe5fb8aea24792524b5b5b6d77 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 30 Sep 2012 23:03:45 +1000 Subject: [PATCH 055/160] Submit shares from stratum through the abstracted submit share function detecting what message they belong to and showing the data from the associated work, and then deleting it from the hash. --- cgminer.c | 34 ++++++++++++++++++++++++++++++---- util.c | 7 ++++--- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/cgminer.c b/cgminer.c index 4d6dd168..d9371370 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1919,7 +1919,7 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub int rolltime; uint32_t *hash32; struct timeval tv_submit, tv_submit_reply; - char hashshow[64+1] = ""; + char hashshow[64 +1 ] = ""; char worktime[200] = ""; #ifdef __BIG_ENDIAN__ @@ -2757,6 +2757,8 @@ static void *submit_work_thread(void *userdata) pool->rpc_user, work->job_id, work->nonce2, work->ntime, noncehex, sshare->id); free(noncehex); + applog(LOG_INFO, "Submitting share %08lx to pool %d", (unsigned long)(hash32[6]), pool->pool_no); + sock_send(pool->sock, s, strlen(s)); goto out; @@ -4030,6 +4032,21 @@ out_unlock: } } +static void stratum_share_result(json_t *val, json_t *res_val, + struct stratum_share *sshare) +{ + struct work *work = &sshare->work; + char hashshow[65]; + uint32_t *hash32; + int intdiff; + + hash32 = (uint32_t *)(work->hash); + intdiff = round(work->work_difficulty); + sprintf(hashshow, "%08lx Diff %d%s", (unsigned long)(hash32[6]), intdiff, + work->block? " BLOCK!" : ""); + share_result(val, res_val, work, hashshow, false, ""); +} + /* 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) @@ -4042,7 +4059,7 @@ static bool parse_stratum_response(char *s) val = JSON_LOADS(s, &err); if (!val) { - applog(LOG_INFO, "JSON decode failed(%d): %s", err.line, err.text);; + applog(LOG_INFO, "JSON decode failed(%d): %s", err.line, err.text); goto out; } @@ -4059,20 +4076,29 @@ static bool parse_stratum_response(char *s) else ss = strdup("(unknown reason)"); - applog(LOG_INFO, "JSON-RPC decode failed: %s", ss); + applog(LOG_INFO, "JSON-RPC non method decode failed: %s", ss); free(ss); goto out; } + id = json_integer_value(id_val); mutex_lock(&sshare_lock); HASH_FIND_INT(stratum_shares, &id, sshare); if (sshare) HASH_DEL(stratum_shares, sshare); mutex_unlock(&sshare_lock); - if (!sshare) + if (!sshare) { + if (json_is_true(res_val)) + applog(LOG_NOTICE, "Accepted untracked stratum share"); + else + applog(LOG_NOTICE, "Rejected untracked stratum share"); goto out; + } + stratum_share_result(val, res_val, sshare); + free(sshare); + ret = true; out: if (val) diff --git a/util.c b/util.c index 542cbc48..ddc563ae 100644 --- a/util.c +++ b/util.c @@ -1065,11 +1065,12 @@ bool parse_method(struct pool *pool, char *s) } method = json_object_get(val, "method"); + if (!method) + goto out; err_val = json_object_get(val, "error"); params = json_object_get(val, "params"); - if (!method || json_is_null(method) || - (err_val && !json_is_null(err_val))) { + if (err_val && !json_is_null(err_val)) { char *ss; if (err_val) @@ -1077,7 +1078,7 @@ bool parse_method(struct pool *pool, char *s) else ss = strdup("(unknown reason)"); - applog(LOG_INFO, "JSON-RPC decode failed: %s", ss); + applog(LOG_INFO, "JSON-RPC method decode failed: %s", ss); free(ss); From b5617734fa2f4d900912a1e98e87fb16a30c6446 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 30 Sep 2012 23:10:43 +1000 Subject: [PATCH 056/160] Provide locking around stratum send operations to avoid races. --- cgminer.c | 2 +- util.c | 21 ++++++++++++++------- util.h | 2 +- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/cgminer.c b/cgminer.c index d9371370..6e65ada5 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2759,7 +2759,7 @@ static void *submit_work_thread(void *userdata) applog(LOG_INFO, "Submitting share %08lx to pool %d", (unsigned long)(hash32[6]), pool->pool_no); - sock_send(pool->sock, s, strlen(s)); + stratum_send(pool, s, strlen(s)); goto out; } diff --git a/util.c b/util.c index ddc563ae..6b08338a 100644 --- a/util.c +++ b/util.c @@ -843,9 +843,11 @@ bool extract_sockaddr(struct pool *pool, char *url) } /* Send a single command across a socket, appending \n to it */ -bool sock_send(int sock, char *s, ssize_t len) +bool stratum_send(struct pool *pool, char *s, ssize_t len) { + SOCKETTYPE sock = pool->sock; ssize_t sent = 0; + bool ret = false; if (opt_protocol) applog(LOG_DEBUG, "SEND: %s", s); @@ -853,15 +855,20 @@ bool sock_send(int sock, char *s, ssize_t len) strcat(s, "\n"); len++; + mutex_lock(&pool->pool_lock); while (len > 0 ) { sent = send(sock, s + sent, len, 0); - if (SOCKETFAIL(sent)) - return false; + if (SOCKETFAIL(sent)) { + ret = false; + goto out_unlock; + } len -= sent; } + ret = true; fsync(sock); - - return true; +out_unlock: + mutex_unlock(&pool->pool_lock); + return ret;; } #define RECVSIZE 8192 @@ -1129,7 +1136,7 @@ bool auth_stratum(struct pool *pool) free(sret); } - if (!sock_send(pool->sock, s, strlen(s))) + if (!stratum_send(pool, s, strlen(s))) goto out; sret = recv_line(pool->sock); @@ -1184,7 +1191,7 @@ bool initiate_stratum(struct pool *pool) goto out; } - if (!sock_send(pool->sock, s, strlen(s))) { + if (!stratum_send(pool, s, strlen(s))) { applog(LOG_DEBUG, "Failed to send s in initiate_stratum"); goto out; } diff --git a/util.h b/util.h index 51b87787..2560552a 100644 --- a/util.h +++ b/util.h @@ -116,7 +116,7 @@ #endif struct pool; -bool sock_send(int sock, char *s, ssize_t len); +bool stratum_send(struct pool *pool, char *s, ssize_t len); char *recv_line(SOCKETTYPE sock); bool parse_method(struct pool *pool, char *s); bool extract_sockaddr(struct pool *pool, char *url); From 6174c80678139f9fb0a89969b361578ec5141530 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 30 Sep 2012 23:36:05 +1000 Subject: [PATCH 057/160] Copy the stratum url to the rpc url to avoid none being set. --- cgminer.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cgminer.c b/cgminer.c index 6e65ada5..5751e1f3 100644 --- a/cgminer.c +++ b/cgminer.c @@ -588,8 +588,10 @@ static char *set_url(char *arg) arg = get_proxy(arg, pool); - if (detect_stratum(pool, arg)) + if (detect_stratum(pool, arg)) { + pool->rpc_url = strdup(pool->stratum_url); return NULL; + } opt_set_charp(arg, &pool->rpc_url); if (strncmp(arg, "http://", 7) && @@ -4286,8 +4288,7 @@ static inline int cp_prio(void) static void pool_resus(struct pool *pool) { - applog(LOG_WARNING, "Pool %d %s alive", pool->pool_no, - pool->has_stratum ? pool->stratum_url : pool->rpc_url); + applog(LOG_WARNING, "Pool %d %s alive", pool->pool_no, pool->rpc_url); if (pool->prio < cp_prio() && pool_strategy == POOL_FAILOVER) switch_pools(NULL); } @@ -5568,7 +5569,8 @@ static bool input_pool(bool live) strncat(httpinput, url, 248); free(url); url = httpinput; - } + } else + url = strdup(pool->stratum_url); add_pool_details(pool, live, url, user, pass); ret = true; From e93f679ae4f0a1320a3a68d20b07f43b34f1a7bf Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 30 Sep 2012 23:44:27 +1000 Subject: [PATCH 058/160] Use the current pool when deciding whether to reuse work from a stratum source rather than the work's previous pool. --- cgminer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cgminer.c b/cgminer.c index 5751e1f3..65ea5d43 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4370,11 +4370,11 @@ static struct work *hash_pop(const struct timespec *abstime) return work; } -static bool reuse_work(struct work *work) +static bool reuse_work(struct work *work, struct pool *pool) { - if (work->stratum && !work->pool->idle) { + if (pool->has_stratum) { applog(LOG_DEBUG, "Reusing stratum work"); - gen_stratum_work(work->pool, work);; + gen_stratum_work(pool, work);; return true; } @@ -4545,7 +4545,7 @@ static void get_work(struct work *work, struct thr_info *thr, const int thr_id) retry: pool = current_pool(); - if (reuse_work(work)) + if (reuse_work(work, pool)) goto out; if (!pool->lagging && !total_staged() && global_queued() >= mining_threads + opt_queue) { From b97a33a58a9195b76e115b98f05ba0593839e6b7 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 1 Oct 2012 14:44:44 +1000 Subject: [PATCH 059/160] Use statically allocated stratum strings in struct work to cope with the inability to safely deallocate dynamically allocated ram. --- cgminer.c | 19 ++++++++++++------- miner.h | 8 +++++--- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/cgminer.c b/cgminer.c index 65ea5d43..cb0ef195 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4444,6 +4444,8 @@ static void gen_stratum_work(struct pool *pool, struct work *work) /* Generate coinbase */ nonce2 = bin2hex((const unsigned char *)&pool->nonce2, pool->n2size); + if (unlikely(!nonce2)) + quit(1, "Failed to convert nonce2 in gen_stratum_work"); pool->nonce2++; cb1_len = strlen(pool->swork.coinbase1) / 2; n1_len = strlen(pool->nonce1) / 2; @@ -4471,6 +4473,8 @@ static void gen_stratum_work(struct pool *pool, struct work *work) for (i = 0; i < 32 / 4; i++) swap32[i] = swab32(data32[i]); merkle_hash = (unsigned char *)bin2hex((const unsigned char *)merkle_root, 32); + if (unlikely(!merkle_hash)) + quit(1, "Failed to conver merkle_hash in gen_stratum_work"); sprintf(header, "%s", pool->swork.bbversion); strcat(header, pool->swork.prev_hash); @@ -4483,9 +4487,10 @@ static void gen_stratum_work(struct pool *pool, struct work *work) diff = pool->swork.diff; /* Copy parameters required for share submission */ - work->job_id = strdup(pool->swork.job_id); - work->nonce2 = nonce2; - work->ntime = pool->swork.ntime; + sprintf(work->job_id, "%s", pool->swork.job_id); + sprintf(work->nonce2, "%s", nonce2); + sprintf(work->ntime, "%s", pool->swork.ntime); + free(nonce2); mutex_unlock(&pool->pool_lock); @@ -4495,11 +4500,11 @@ static void gen_stratum_work(struct pool *pool, struct work *work) free(merkle_hash); /* Convert hex data to binary data for work */ - if (!hex2bin(work->data, header, 128)) + if (unlikely(!hex2bin(work->data, header, 128))) quit(1, "Failed to convert header to data in gen_stratum_work"); calc_midstate(work); sprintf(hash1, "00000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000010000"); - if (!hex2bin(work->hash1, hash1, 64)) + if (unlikely(!hex2bin(work->hash1, hash1, 64))) quit(1, "Failed to convert hash1 in gen_stratum_work"); /* Generate target as hex where 0x00000000FFFFFFFF is diff 1 */ @@ -4507,12 +4512,12 @@ static void gen_stratum_work(struct pool *pool, struct work *work) diff64 = ~htobe64(diff64); sprintf(target, "ffffffffffffffffffffffffffffffffffffffffffffffff"); buf = bin2hex((const unsigned char *)&diff64, 8); - if (!buf) + if (unlikely(!buf)) quit(1, "Failed to convert diff64 to buf in gen_stratum_work"); strcat(target, buf); free(buf); applog(LOG_DEBUG, "Generated target %s", target); - if (!hex2bin(work->target, target, 32)) + if (unlikely(!hex2bin(work->target, target, 32))) quit(1, "Failed to convert target to bin in gen_stratum_work"); work->pool = pool; diff --git a/miner.h b/miner.h index e216be6a..fb30ac94 100644 --- a/miner.h +++ b/miner.h @@ -880,9 +880,11 @@ struct work { bool queued; bool stratum; - char *job_id; - char *nonce2; - char *ntime; + /* These are arbitrary lengths as it is too hard to keep track of + * dynamically allocated ram in work structs */ + char job_id[64]; + char nonce2[64]; + char ntime[16]; unsigned int work_block; int id; From 90b189374681f1e77f18e6200229fa012b4df8ae Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 1 Oct 2012 18:43:24 +1000 Subject: [PATCH 060/160] Create a work item from a "clean" request from stratum allowing the new block to be detected and the appropriate block change message to be given. --- cgminer.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/cgminer.c b/cgminer.c index cb0ef195..af8c63ac 100644 --- a/cgminer.c +++ b/cgminer.c @@ -3043,17 +3043,18 @@ static int block_sort(struct block *blocka, struct block *blockb) return blocka->block_no - blockb->block_no; } -static void test_work_current(struct work *work) +static bool test_work_current(struct work *work) { + bool ret = true; char *hexstr; if (work->mandatory) - return; + return ret; hexstr = bin2hex(work->data, 18); if (unlikely(!hexstr)) { applog(LOG_ERR, "stage_thread OOM"); - return; + return ret; } /* Search to see if this block exists yet and if not, consider it a @@ -3061,6 +3062,7 @@ static void test_work_current(struct work *work) if (!block_exists(hexstr)) { struct block *s = calloc(sizeof(struct block), 1); int deleted_block = 0; + ret = false; if (unlikely(!s)) quit (1, "test_work_current OOM"); @@ -3098,8 +3100,8 @@ static void test_work_current(struct work *work) applog(LOG_NOTICE, "New block detected on network before longpoll"); else applog(LOG_NOTICE, "New block detected on network"); - restart_threads(); } + restart_threads(); } else if (work->longpoll) { work->longpoll = false; if (work->pool == current_pool()) { @@ -3111,6 +3113,7 @@ static void test_work_current(struct work *work) } out_free: free(hexstr); + return ret; } static int tv_sort(struct work *worka, struct work *workb) @@ -4145,10 +4148,20 @@ static void *stratum_thread(void *userdata) if (!parse_method(pool, s) && !parse_stratum_response(s)) applog(LOG_INFO, "Unknown stratum msg: %s", s); free(s); - if (unlikely(pool->swork.clean)) { + if (pool->swork.clean) { + struct work work; + + /* Generate a single work item to update the current + * block database */ pool->swork.clean = false; - applog(LOG_NOTICE, "Stratum requested work restart for block change"); - restart_threads(); + gen_stratum_work(pool, &work); + if (test_work_current(&work)) { + if (pool == current_pool()) { + restart_threads(); + applog(LOG_NOTICE, "Stratum requested work restart for block change"); + } + } else + applog(LOG_NOTICE, "Stratum from pool %d detected new block", pool->pool_no); } if (unlikely(pool->removed)) { From 2aacd89aa8fa5ea72a114c252120c446ad08d1a6 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 1 Oct 2012 18:46:33 +1000 Subject: [PATCH 061/160] Minor message change. --- cgminer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index af8c63ac..71021a40 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4158,7 +4158,7 @@ static void *stratum_thread(void *userdata) if (test_work_current(&work)) { if (pool == current_pool()) { restart_threads(); - applog(LOG_NOTICE, "Stratum requested work restart for block change"); + applog(LOG_NOTICE, "Stratum requested work restart"); } } else applog(LOG_NOTICE, "Stratum from pool %d detected new block", pool->pool_no); From b495a51b76ab024174d31f7077b25f9526ad4791 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 1 Oct 2012 18:50:32 +1000 Subject: [PATCH 062/160] Comment update. --- cgminer.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 71021a40..64262320 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4156,9 +4156,11 @@ static void *stratum_thread(void *userdata) pool->swork.clean = false; gen_stratum_work(pool, &work); if (test_work_current(&work)) { + /* Only accept a work restart if this stratum + * connection is from the current pool */ if (pool == current_pool()) { restart_threads(); - applog(LOG_NOTICE, "Stratum requested work restart"); + applog(LOG_NOTICE, "Stratum from pool %d requested work restart", pool->pool_no); } } else applog(LOG_NOTICE, "Stratum from pool %d detected new block", pool->pool_no); From eaf7ed0dcd4004ef9908c4cf968571e7df9c93fb Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 1 Oct 2012 22:13:20 +1000 Subject: [PATCH 063/160] Detect if a getwork based pool has the X-Stratum header on startup, and if so, switch to the stratum based pool. --- cgminer.c | 18 +++++++++++++++++- util.c | 24 ++++++++++++++++++++---- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/cgminer.c b/cgminer.c index 64262320..894c3cd6 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4192,6 +4192,9 @@ static bool pool_active(struct pool *pool, bool pinging) CURL *curl; int rolltime; + applog(LOG_INFO, "Testing pool %s", pool->rpc_url); + +retry_stratum: if (pool->has_stratum) { if ((!pool->stratum_active || pinging) && !initiate_stratum(pool)) return false; @@ -4212,12 +4215,25 @@ static bool pool_active(struct pool *pool, bool pinging) return false; } - applog(LOG_INFO, "Testing pool %s", pool->rpc_url); gettimeofday(&tv_getwork, NULL); val = json_rpc_call(curl, pool->rpc_url, pool->rpc_userpass, 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, + * and if so, switch to that in preference to getwork */ + if (unlikely(!pinging && pool->stratum_url)) { + applog(LOG_NOTICE, "Switching pool %d %s to %s", pool->pool_no, pool->rpc_url, pool->stratum_url); + pool->has_stratum = true; + pool->rpc_url = strdup(pool->stratum_url); + extract_sockaddr(pool, pool->stratum_url); + initiate_stratum(pool); + auth_stratum(pool); + curl_easy_cleanup(curl); + + goto retry_stratum; + } + if (val) { struct work *work = make_work(); bool rc; diff --git a/util.c b/util.c index 6b08338a..b81af61d 100644 --- a/util.c +++ b/util.c @@ -54,6 +54,7 @@ struct header_info { char *lp_path; int rolltime; char *reason; + char *stratum_url; bool hadrolltime; bool canroll; bool hadexpire; @@ -183,6 +184,11 @@ static size_t resp_hdr_cb(void *ptr, size_t size, size_t nmemb, void *user_data) val = NULL; } + if (!strcasecmp("X-Stratum", key)) { + hi->stratum_url = val; + val = NULL; + } + out: free(key); free(val); @@ -261,7 +267,7 @@ json_t *json_rpc_call(CURL *curl, const char *url, { long timeout = longpoll ? (60 * 60) : 60; struct data_buffer all_data = {NULL, 0}; - struct header_info hi = {NULL, 0, NULL, false, false, false}; + struct header_info hi = {NULL, 0, NULL, NULL, false, false, false}; char len_hdr[64], user_agent_hdr[128]; char curl_err_str[CURL_ERROR_SIZE]; struct curl_slist *headers = NULL; @@ -388,9 +394,19 @@ json_t *json_rpc_call(CURL *curl, const char *url, pool->hdr_path = hi.lp_path; } else pool->hdr_path = NULL; - } else if (hi.lp_path) { - free(hi.lp_path); - hi.lp_path = NULL; + if (hi.stratum_url) { + pool->stratum_url = hi.stratum_url; + hi.stratum_url = NULL; + } + } else { + if (hi.lp_path) { + free(hi.lp_path); + hi.lp_path = NULL; + } + if (hi.stratum_url) { + free(hi.stratum_url); + hi.stratum_url = NULL; + } } *rolltime = hi.rolltime; From 4a7ce9dd2a0e9dd100cda850cdc8ae0da08540c5 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 1 Oct 2012 22:21:43 +1000 Subject: [PATCH 064/160] Avoid duplicating pool->rpc_url and setting pool->stratum_url twice to itself. --- cgminer.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index 894c3cd6..b11af03d 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4225,8 +4225,10 @@ retry_stratum: if (unlikely(!pinging && pool->stratum_url)) { applog(LOG_NOTICE, "Switching pool %d %s to %s", pool->pool_no, pool->rpc_url, pool->stratum_url); pool->has_stratum = true; - pool->rpc_url = strdup(pool->stratum_url); - extract_sockaddr(pool, pool->stratum_url); + pool->rpc_url = pool->stratum_url; + /* pool->stratum_url will be set again in extract_sockaddr */ + pool->stratum_url = NULL; + extract_sockaddr(pool, pool->rpc_url); initiate_stratum(pool); auth_stratum(pool); curl_easy_cleanup(curl); From 601d1aca9764e3fa5697d8d151a6898b8a0743db Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 1 Oct 2012 23:15:50 +1000 Subject: [PATCH 065/160] Allow the stratum retry to initiate and auth stratum in pool_alive to make sure the stratum thread is started. --- cgminer.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index b11af03d..328b083c 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4229,8 +4229,6 @@ retry_stratum: /* pool->stratum_url will be set again in extract_sockaddr */ pool->stratum_url = NULL; extract_sockaddr(pool, pool->rpc_url); - initiate_stratum(pool); - auth_stratum(pool); curl_easy_cleanup(curl); goto retry_stratum; From 2ccb6d78ca83d6906e3d57d92cdb8f620c782da7 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 1 Oct 2012 23:19:34 +1000 Subject: [PATCH 066/160] Decrease the queued count with stratum work once it's staged as well. --- cgminer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cgminer.c b/cgminer.c index 328b083c..16c3955d 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2583,6 +2583,7 @@ static void *get_work_thread(void *userdata) kill_work(); free(ret_work); } + dec_queued(pool); goto out; } From 2941febd0584d815b8fbbaf42348ebcf24b57acf Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 2 Oct 2012 00:00:55 +1000 Subject: [PATCH 067/160] Store a sockaddr url of the stripped url used in determining sockaddr to not confuse it with the stratum url and fix build warnings. --- cgminer.c | 9 ++++----- miner.h | 1 + util.c | 7 ++++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/cgminer.c b/cgminer.c index 16c3955d..db132b13 100644 --- a/cgminer.c +++ b/cgminer.c @@ -5594,9 +5594,9 @@ static bool input_pool(bool live) pool = add_pool(); - if (!detect_stratum(pool, url) && - strncmp(url, "http://", 7) && - strncmp(url, "https://", 8)) { + if (detect_stratum(pool, url)) + url = strdup(pool->stratum_url); + else if (strncmp(url, "http://", 7) && strncmp(url, "https://", 8)) { char *httpinput; httpinput = malloc(255); @@ -5606,8 +5606,7 @@ static bool input_pool(bool live) strncat(httpinput, url, 248); free(url); url = httpinput; - } else - url = strdup(pool->stratum_url); + } add_pool_details(pool, live, url, user, pass); ret = true; diff --git a/miner.h b/miner.h index fb30ac94..9143ebc8 100644 --- a/miner.h +++ b/miner.h @@ -834,6 +834,7 @@ struct pool { char *stratum_url; SOCKETTYPE sock; struct sockaddr_in *server, client; + char *sockaddr_url; /* stripped url used for sockaddr */ char *subscription; char *nonce1; uint32_t nonce2; diff --git a/util.c b/util.c index b81af61d..89d7a0fd 100644 --- a/util.c +++ b/util.c @@ -809,7 +809,7 @@ double tdiff(struct timeval *end, struct timeval *start) bool extract_sockaddr(struct pool *pool, char *url) { - char *url_begin, *url_end, *port_start; + char *url_begin, *url_end, *port_start = NULL; char *url_address, *port; struct addrinfo hints, *res; int url_len, port_len = 0; @@ -854,7 +854,7 @@ bool extract_sockaddr(struct pool *pool, char *url) } pool->server = (struct sockaddr_in *)res->ai_addr; - pool->stratum_url = strdup(url_address); + pool->sockaddr_url = strdup(url_address); return true; } @@ -1188,7 +1188,7 @@ out: bool initiate_stratum(struct pool *pool) { - json_t *val, *res_val, *err_val, *notify_val; + json_t *val = NULL, *res_val, *err_val, *notify_val; char *s, *buf, *sret = NULL; json_error_t err; bool ret = false; @@ -1281,6 +1281,7 @@ out: json_decref(val); if (ret) { + pool->stratum_url = pool->sockaddr_url; pool->stratum_active = true; pool->swork.diff = 1; if (opt_protocol) { From df91df3507f94b6a853b98e1255d761bb1c88475 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 2 Oct 2012 02:03:52 +1000 Subject: [PATCH 068/160] Userpass needs to be copied to user and pass earlier to allow stratum authorisation to work with it. --- cgminer.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cgminer.c b/cgminer.c index db132b13..7c3d2d16 100644 --- a/cgminer.c +++ b/cgminer.c @@ -644,6 +644,7 @@ static char *set_pass(const char *arg) static char *set_userpass(const char *arg) { struct pool *pool; + char *updup; if (total_users || total_passes) return "Use only user + pass or userpass, but not both"; @@ -652,7 +653,14 @@ static char *set_userpass(const char *arg) add_pool(); pool = pools[total_userpasses - 1]; + updup = strdup(arg); opt_set_charp(arg, &pool->rpc_userpass); + pool->rpc_user = strtok(updup, ":"); + if (!pool->rpc_user) + return "Failed to find : delimited user info"; + pool->rpc_pass = strtok(NULL, ":"); + if (!pool->rpc_pass) + return "Failed to find : delimited pass info"; return NULL; } @@ -6085,14 +6093,6 @@ int main(int argc, char *argv[]) if (!pool->rpc_userpass) quit(1, "Failed to malloc userpass"); sprintf(pool->rpc_userpass, "%s:%s", pool->rpc_user, pool->rpc_pass); - } else { - pool->rpc_user = malloc(strlen(pool->rpc_userpass) + 1); - if (!pool->rpc_user) - quit(1, "Failed to malloc user"); - strcpy(pool->rpc_user, pool->rpc_userpass); - pool->rpc_user = strtok(pool->rpc_user, ":"); - if (!pool->rpc_user) - quit(1, "Failed to find colon delimiter in userpass"); } } /* Set the currentpool to pool 0 */ From bbb092e0daf19cba598583ee4bab43aaced53a89 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 2 Oct 2012 09:08:47 +1000 Subject: [PATCH 069/160] Make the stratum recv buffer larger than the recvsize. --- util.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/util.c b/util.c index 89d7a0fd..0afd6fb8 100644 --- a/util.c +++ b/util.c @@ -887,7 +887,7 @@ out_unlock: return ret;; } -#define RECVSIZE 8192 +#define RECVSIZE 8191 static void clear_sock(SOCKETTYPE sock) { @@ -921,7 +921,7 @@ char *recv_line(SOCKETTYPE sock) char *sret = NULL, *s, c; ssize_t offset = 0; - s = alloca(RECVSIZE); + s = alloca(RECVSIZE + 1); if (SOCKETFAIL(recv(sock, s, RECVSIZE, MSG_PEEK))) { applog(LOG_DEBUG, "Failed to recv sock in recv_line"); goto out; @@ -1136,7 +1136,7 @@ bool auth_stratum(struct pool *pool) json_error_t err; bool ret = false; - s = alloca(RECVSIZE); + s = alloca(RECVSIZE + 1); sprintf(s, "{\"id\": %d, \"method\": \"mining.authorize\", \"params\": [\"%s\", \"%s\"]}", swork_id++, pool->rpc_user, pool->rpc_pass); @@ -1196,7 +1196,7 @@ bool initiate_stratum(struct pool *pool) if (pool->stratum_active) return true; - s = alloca(RECVSIZE); + s = alloca(RECVSIZE + 1); sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": []}", swork_id++); pool->sock = socket(AF_INET, SOCK_STREAM, 0); From 78aafcec5c05c611f4579bc6a82100f3889c7716 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 2 Oct 2012 09:26:18 +1000 Subject: [PATCH 070/160] Make all buffers slightly larger to prevent overflow. --- cgminer.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cgminer.c b/cgminer.c index 7c3d2d16..20b7436a 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1929,7 +1929,7 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub int rolltime; uint32_t *hash32; struct timeval tv_submit, tv_submit_reply; - char hashshow[64 +1 ] = ""; + char hashshow[64 + 1] = ""; char worktime[200] = ""; #ifdef __BIG_ENDIAN__ @@ -4465,7 +4465,7 @@ static struct work *clone_work(struct work *work) static void gen_hash(unsigned char *data, unsigned char *hash, int len) { - unsigned char hash1[32]; + unsigned char hash1[33]; sha2(data, len, hash1, false); sha2(hash1, 32, hash, false); @@ -4473,11 +4473,11 @@ static void gen_hash(unsigned char *data, unsigned char *hash, int len) static void gen_stratum_work(struct pool *pool, struct work *work) { - char header[256], hash1[128], *nonce2, *buf; - unsigned char *coinbase, merkle_root[32], merkle_sha[64], *merkle_hash; + char header[257], hash1[129], *nonce2, *buf; + unsigned char *coinbase, merkle_root[33], merkle_sha[65], *merkle_hash; uint32_t *data32, *swap32; uint64_t diff, diff64; - char target[64]; + char target[65]; int len, cb1_len, n1_len, cb2_len, i; mutex_lock(&pool->pool_lock); @@ -4491,7 +4491,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work) n1_len = strlen(pool->nonce1) / 2; cb2_len = strlen(pool->swork.coinbase2) / 2; len = cb1_len + n1_len + pool->n2size + cb2_len; - coinbase = alloca(len); + coinbase = alloca(len + 1); hex2bin(coinbase, pool->swork.coinbase1, cb1_len); hex2bin(coinbase + cb1_len, pool->nonce1, n1_len); hex2bin(coinbase + cb1_len + n1_len, nonce2, pool->n2size); @@ -4501,7 +4501,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work) gen_hash(coinbase, merkle_root, len); memcpy(merkle_sha, merkle_root, 32); for (i = 0; i < pool->swork.merkles; i++) { - unsigned char merkle_bin[32]; + unsigned char merkle_bin[33]; hex2bin(merkle_bin, pool->swork.merkle[i], 32); memcpy(merkle_sha + 32, merkle_bin, 32); From 210bc9be3e04402036d773ef7ab9e185354962ae Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 2 Oct 2012 10:02:25 +1000 Subject: [PATCH 071/160] If no stratum url is set by the end of the detect stratum routine, copy the sockaddr url. --- cgminer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cgminer.c b/cgminer.c index 20b7436a..f01ee154 100644 --- a/cgminer.c +++ b/cgminer.c @@ -571,6 +571,8 @@ bool detect_stratum(struct pool *pool, char *url) if (!strncasecmp(url, "stratum+tcp://", 14) || stratum) { pool->has_stratum = true; + if (!pool->stratum_url) + pool->stratum_url = pool->sockaddr_url; return true; } From 496af92afd3e2cfe0d507e7199bc35b17ecee766 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 2 Oct 2012 10:06:37 +1000 Subject: [PATCH 072/160] Don't wait on select when first detecting stratum, just receive one line. --- util.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/util.c b/util.c index 0afd6fb8..13fc2bb2 100644 --- a/util.c +++ b/util.c @@ -897,18 +897,14 @@ static void clear_sock(SOCKETTYPE sock) } /* Check to see if Santa's been good to you */ -static bool sock_full(SOCKETTYPE sock, bool wait) +static bool sock_full(SOCKETTYPE sock) { struct timeval timeout; fd_set rd; FD_ZERO(&rd); FD_SET(sock, &rd); - timeout.tv_usec = 0; - if (wait) - timeout.tv_sec = 60; - else - timeout.tv_sec = 0; + timeout.tv_usec = timeout.tv_sec = 0; if (select(sock + 1, &rd, NULL, NULL, &timeout) > 0) return true; return false; @@ -1141,7 +1137,7 @@ bool auth_stratum(struct pool *pool) swork_id++, pool->rpc_user, pool->rpc_pass); /* Parse all data prior sending auth request */ - while (sock_full(pool->sock, false)) { + while (sock_full(pool->sock)) { sret = recv_line(pool->sock); if (!parse_method(pool, sret)) { clear_sock(pool->sock); @@ -1212,11 +1208,6 @@ bool initiate_stratum(struct pool *pool) goto out; } - if (!sock_full(pool->sock, true)) { - applog(LOG_DEBUG, "Timed out waiting for response in initiate_stratum"); - goto out; - } - sret = recv_line(pool->sock); if (!sret) goto out; From d851bf3d65fa87e2aa3e4e1aa2b3fca2d29093fe Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 2 Oct 2012 10:10:52 +1000 Subject: [PATCH 073/160] Revert "Don't wait on select when first detecting stratum, just receive one line." This reverts commit 496af92afd3e2cfe0d507e7199bc35b17ecee766. Not quite right. --- util.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/util.c b/util.c index 13fc2bb2..0afd6fb8 100644 --- a/util.c +++ b/util.c @@ -897,14 +897,18 @@ static void clear_sock(SOCKETTYPE sock) } /* Check to see if Santa's been good to you */ -static bool sock_full(SOCKETTYPE sock) +static bool sock_full(SOCKETTYPE sock, bool wait) { struct timeval timeout; fd_set rd; FD_ZERO(&rd); FD_SET(sock, &rd); - timeout.tv_usec = timeout.tv_sec = 0; + timeout.tv_usec = 0; + if (wait) + timeout.tv_sec = 60; + else + timeout.tv_sec = 0; if (select(sock + 1, &rd, NULL, NULL, &timeout) > 0) return true; return false; @@ -1137,7 +1141,7 @@ bool auth_stratum(struct pool *pool) swork_id++, pool->rpc_user, pool->rpc_pass); /* Parse all data prior sending auth request */ - while (sock_full(pool->sock)) { + while (sock_full(pool->sock, false)) { sret = recv_line(pool->sock); if (!parse_method(pool, sret)) { clear_sock(pool->sock); @@ -1208,6 +1212,11 @@ bool initiate_stratum(struct pool *pool) goto out; } + if (!sock_full(pool->sock, true)) { + applog(LOG_DEBUG, "Timed out waiting for response in initiate_stratum"); + goto out; + } + sret = recv_line(pool->sock); if (!sret) goto out; From d122a789edf2b2800117381dd1991ef31f97e264 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 2 Oct 2012 10:19:45 +1000 Subject: [PATCH 074/160] Use 5 second timeout on sock full for now as a temporary workaround. --- util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util.c b/util.c index 0afd6fb8..467b863b 100644 --- a/util.c +++ b/util.c @@ -906,7 +906,7 @@ static bool sock_full(SOCKETTYPE sock, bool wait) FD_SET(sock, &rd); timeout.tv_usec = 0; if (wait) - timeout.tv_sec = 60; + timeout.tv_sec = 5; else timeout.tv_sec = 0; if (select(sock + 1, &rd, NULL, NULL, &timeout) > 0) From 1b7aa48c8fdfac32e5370aaa03b41f39c3cdbfbd Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 2 Oct 2012 11:46:48 +1000 Subject: [PATCH 075/160] Initiate stratum the first time in pool_active only, allowing us to switch to it on getting a failed getwork and detecting the presence of stratum on the url at that time. --- cgminer.c | 18 ++++++++++-------- util.c | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/cgminer.c b/cgminer.c index f01ee154..3824a509 100644 --- a/cgminer.c +++ b/cgminer.c @@ -562,17 +562,12 @@ static char *set_rr(enum pool_strategy *strategy) * stratum+tcp or by detecting a stratum server response */ bool detect_stratum(struct pool *pool, char *url) { - bool stratum; - if (!extract_sockaddr(pool, url)) return false; - stratum = initiate_stratum(pool); - - if (!strncasecmp(url, "stratum+tcp://", 14) || stratum) { + if (!strncasecmp(url, "stratum+tcp://", 14)) { pool->has_stratum = true; - if (!pool->stratum_url) - pool->stratum_url = pool->sockaddr_url; + pool->stratum_url = pool->sockaddr_url; return true; } @@ -4205,6 +4200,7 @@ static bool pool_active(struct pool *pool, bool pinging) applog(LOG_INFO, "Testing pool %s", pool->rpc_url); + /* This is the central point we activate stratum when we can */ retry_stratum: if (pool->has_stratum) { if ((!pool->stratum_active || pinging) && !initiate_stratum(pool)) @@ -4233,7 +4229,7 @@ retry_stratum: /* Detect if a http getwork pool has an X-Stratum header at startup, * and if so, switch to that in preference to getwork */ - if (unlikely(!pinging && pool->stratum_url)) { + if (unlikely(pool->stratum_url)) { applog(LOG_NOTICE, "Switching pool %d %s to %s", pool->pool_no, pool->rpc_url, pool->stratum_url); pool->has_stratum = true; pool->rpc_url = pool->stratum_url; @@ -4308,6 +4304,12 @@ retry_stratum: quit(1, "Failed to create pool longpoll thread"); } } else { + /* If we failed to parse a getwork, this could be a stratum + * url without the prefix stratum+tcp:// so let's check it */ + if (initiate_stratum(pool)) { + pool->has_stratum = true; + goto retry_stratum; + } applog(LOG_DEBUG, "FAILED to retrieve work from pool %u %s", pool->pool_no, pool->rpc_url); if (!pinging) diff --git a/util.c b/util.c index 467b863b..0afd6fb8 100644 --- a/util.c +++ b/util.c @@ -906,7 +906,7 @@ static bool sock_full(SOCKETTYPE sock, bool wait) FD_SET(sock, &rd); timeout.tv_usec = 0; if (wait) - timeout.tv_sec = 5; + timeout.tv_sec = 60; else timeout.tv_sec = 0; if (select(sock + 1, &rd, NULL, NULL, &timeout) > 0) From 925d01922b94e541bcdfbdc342b9670f6b12fe55 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 2 Oct 2012 14:12:34 +1000 Subject: [PATCH 076/160] If a share result has an error code but still has an id, it is likely a reject, not an error. --- cgminer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 3824a509..bda51596 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4079,7 +4079,7 @@ static bool parse_stratum_response(char *s) id_val = json_object_get(val, "id"); if ((!res_val || !id_val) || (json_is_null(res_val) || json_is_null(id_val)) || - (err_val && !json_is_null(err_val))) { + (err_val && !json_is_null(err_val) && !id)) { char *ss; if (err_val) From a8a8ed6207eda600f2894e3809c7ea2250af43a4 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 2 Oct 2012 16:01:32 +1000 Subject: [PATCH 077/160] Correct target calculation in gen_stratum_work. --- cgminer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index bda51596..3b369469 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4552,7 +4552,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work) quit(1, "Failed to convert hash1 in gen_stratum_work"); /* Generate target as hex where 0x00000000FFFFFFFF is diff 1 */ - diff64 = 0x00000000FFFFFFFFULL * diff; + diff64 = (1Ull << (31 + diff)) - 1; diff64 = ~htobe64(diff64); sprintf(target, "ffffffffffffffffffffffffffffffffffffffffffffffff"); buf = bin2hex((const unsigned char *)&diff64, 8); From fdaabf59c6fd51b4cfb2a8209ab00b93590b7764 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 3 Oct 2012 00:35:08 +1000 Subject: [PATCH 078/160] Make target on stratum scale to any size by clearing sequential bits according to diff. --- cgminer.c | 40 ++++++++++++++++++++++++---------------- miner.h | 15 +++++++++++++++ 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/cgminer.c b/cgminer.c index 3b369469..a2c33920 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4477,12 +4477,13 @@ static void gen_hash(unsigned char *data, unsigned char *hash, int len) static void gen_stratum_work(struct pool *pool, struct work *work) { - char header[257], hash1[129], *nonce2, *buf; unsigned char *coinbase, merkle_root[33], merkle_sha[65], *merkle_hash; + int len, cb1_len, n1_len, cb2_len, i, j; + unsigned char rtarget[33], target[33]; + char header[257], hash1[129], *nonce2; uint32_t *data32, *swap32; - uint64_t diff, diff64; - char target[65]; - int len, cb1_len, n1_len, cb2_len, i; + uint8_t *data8; + int diff; mutex_lock(&pool->pool_lock); @@ -4551,18 +4552,25 @@ static void gen_stratum_work(struct pool *pool, struct work *work) if (unlikely(!hex2bin(work->hash1, hash1, 64))) quit(1, "Failed to convert hash1 in gen_stratum_work"); - /* Generate target as hex where 0x00000000FFFFFFFF is diff 1 */ - diff64 = (1Ull << (31 + diff)) - 1; - diff64 = ~htobe64(diff64); - sprintf(target, "ffffffffffffffffffffffffffffffffffffffffffffffff"); - buf = bin2hex((const unsigned char *)&diff64, 8); - if (unlikely(!buf)) - quit(1, "Failed to convert diff64 to buf in gen_stratum_work"); - strcat(target, buf); - free(buf); - applog(LOG_DEBUG, "Generated target %s", target); - if (unlikely(!hex2bin(work->target, target, 32))) - quit(1, "Failed to convert target to bin in gen_stratum_work"); + /* Scale to any diff by setting number of bits according to diff */ + hex2bin(rtarget, "00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 32); + data8 = (uint8_t *)(rtarget + 4); + for (i = 1, j = 0; i < diff; i++, j++) { + int byte = j / 8; + int bit = j % 8; + + data8[byte] &= ~(8 >> bit); + } + swab256(target, rtarget); + if (opt_debug) { + char *htarget = bin2hex(target, 32); + + if (likely(htarget)) { + applog(LOG_DEBUG, "Generated target %s", htarget); + free(htarget); + } + } + memcpy(work->target, target, 256); work->pool = pool; work->stratum = true; diff --git a/miner.h b/miner.h index 9143ebc8..78565f77 100644 --- a/miner.h +++ b/miner.h @@ -511,6 +511,21 @@ static inline void swap256(void *dest_p, const void *src_p) dest[7] = src[0]; } +static inline void swab256(void *dest_p, const void *src_p) +{ + uint32_t *dest = dest_p; + const uint32_t *src = src_p; + + dest[0] = swab32(src[7]); + dest[1] = swab32(src[6]); + dest[2] = swab32(src[5]); + dest[3] = swab32(src[4]); + dest[4] = swab32(src[3]); + dest[5] = swab32(src[2]); + dest[6] = swab32(src[1]); + dest[7] = swab32(src[0]); +} + extern void quit(int status, const char *format, ...); static inline void mutex_lock(pthread_mutex_t *lock) From 9e0e61509d7bd78edbdac15b53bc8a6e9187043e Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 3 Oct 2012 01:14:35 +1000 Subject: [PATCH 079/160] We should be testing for id_val, not id in parse stratum response. --- cgminer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index a2c33920..f0df2848 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4079,7 +4079,7 @@ static bool parse_stratum_response(char *s) id_val = json_object_get(val, "id"); if ((!res_val || !id_val) || (json_is_null(res_val) || json_is_null(id_val)) || - (err_val && !json_is_null(err_val) && !id)) { + (err_val && !json_is_null(err_val) && !id_val)) { char *ss; if (err_val) From c6a3d065fa6c19191af3709fc5b138faf0c0fafb Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 3 Oct 2012 08:55:02 +1000 Subject: [PATCH 080/160] Parse reject reason from the stratum json error code if there is one. --- cgminer.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cgminer.c b/cgminer.c index f0df2848..653c2b1f 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1885,6 +1885,18 @@ share_result(json_t *val, json_t *res, const struct work *work, char *hashshow, reason[reasonLen + 2] = ')'; reason[reasonLen + 3] = '\0'; memcpy(disposition + 7, reasontmp, reasonLen); disposition[6] = ':'; disposition[reasonLen + 7] = '\0'; + } else if (work->stratum) { + json_t *arr_val = json_object_get(val, "error"); + + if (likely(json_is_array(arr_val))) { + char *json_reason = (char *)json_string_value(json_array_get(arr_val, 1)); + + if (likely(json_reason)) { + snprintf(reason, 31, "%s", json_reason); + free(json_reason); + } + } + } else strcpy(reason, ""); From 74c11945f07fe02ba4962b379c8f1fbf51a68b1c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 3 Oct 2012 09:42:20 +1000 Subject: [PATCH 081/160] Offset the current block detection to the prev block hash. --- cgminer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index 653c2b1f..7bdf6403 100644 --- a/cgminer.c +++ b/cgminer.c @@ -3044,7 +3044,7 @@ static bool block_exists(char *hexstr) /* Tests if this work is from a block that has been seen before */ static inline bool from_existing_block(struct work *work) { - char *hexstr = bin2hex(work->data, 18); + char *hexstr = bin2hex(work->data + 8, 18); bool ret; if (unlikely(!hexstr)) { @@ -3069,7 +3069,7 @@ static bool test_work_current(struct work *work) if (work->mandatory) return ret; - hexstr = bin2hex(work->data, 18); + hexstr = bin2hex(work->data + 8, 18); if (unlikely(!hexstr)) { applog(LOG_ERR, "stage_thread OOM"); return ret; From 3d982dfbe935e07206735f830f0bb80e1d93b2ab Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 3 Oct 2012 09:49:01 +1000 Subject: [PATCH 082/160] Set work_block in gen_stratum_work for when work is reused to avoid thinking it's all stale. --- cgminer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cgminer.c b/cgminer.c index 7bdf6403..9f63be84 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4590,6 +4590,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work) work->id = total_work++; work->longpoll = false; work->getwork_mode = GETWORK_MODE_STRATUM; + work->work_block = work_block; calc_diff(work, diff); gettimeofday(&work->tv_staged, NULL); From 310239b8e892caca3be084f98ea3ee4ac87e3040 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 3 Oct 2012 10:20:54 +1000 Subject: [PATCH 083/160] Revert "Parse reject reason from the stratum json error code if there is one." This reverts commit c6a3d065fa6c19191af3709fc5b138faf0c0fafb. Segfaults. Needs work. --- cgminer.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/cgminer.c b/cgminer.c index 9f63be84..6891b245 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1885,18 +1885,6 @@ share_result(json_t *val, json_t *res, const struct work *work, char *hashshow, reason[reasonLen + 2] = ')'; reason[reasonLen + 3] = '\0'; memcpy(disposition + 7, reasontmp, reasonLen); disposition[6] = ':'; disposition[reasonLen + 7] = '\0'; - } else if (work->stratum) { - json_t *arr_val = json_object_get(val, "error"); - - if (likely(json_is_array(arr_val))) { - char *json_reason = (char *)json_string_value(json_array_get(arr_val, 1)); - - if (likely(json_reason)) { - snprintf(reason, 31, "%s", json_reason); - free(json_reason); - } - } - } else strcpy(reason, ""); From ac0c813f9d3216c2efadc1e9335b45052a070c6f Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 3 Oct 2012 10:33:11 +1000 Subject: [PATCH 084/160] Bit error in target calculation for stratum. --- cgminer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 6891b245..b1c2867c 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4559,7 +4559,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work) int byte = j / 8; int bit = j % 8; - data8[byte] &= ~(8 >> bit); + data8[byte] &= ~(128 >> bit); } swab256(target, rtarget); if (opt_debug) { From 284b786da7b07e3fd775ed1c4662b88c8444a579 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 3 Oct 2012 11:18:08 +1000 Subject: [PATCH 085/160] Check the stratum pool difference has not changed compared to the work diff when testing whether a share meets the target or not and retarget if necessary. --- cgminer.c | 74 +++++++++++++++++++++++++++++++++++-------------------- miner.h | 1 + 2 files changed, 48 insertions(+), 27 deletions(-) diff --git a/cgminer.c b/cgminer.c index b1c2867c..a78b1a21 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4475,15 +4475,39 @@ static void gen_hash(unsigned char *data, unsigned char *hash, int len) sha2(hash1, 32, hash, false); } +static void set_work_target(struct work *work, int diff) +{ + unsigned char rtarget[33], target[33]; + uint8_t *data8; + int i, j; + + /* Scale to any diff by setting number of bits according to diff */ + hex2bin(rtarget, "00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 32); + data8 = (uint8_t *)(rtarget + 4); + for (i = 1, j = 0; i < diff; i++, j++) { + int byte = j / 8; + int bit = j % 8; + + data8[byte] &= ~(128 >> bit); + } + swab256(target, rtarget); + if (opt_debug) { + char *htarget = bin2hex(target, 32); + + if (likely(htarget)) { + applog(LOG_DEBUG, "Generated target %s", htarget); + free(htarget); + } + } + memcpy(work->target, target, 256); +} + static void gen_stratum_work(struct pool *pool, struct work *work) { unsigned char *coinbase, merkle_root[33], merkle_sha[65], *merkle_hash; - int len, cb1_len, n1_len, cb2_len, i, j; - unsigned char rtarget[33], target[33]; char header[257], hash1[129], *nonce2; + int len, cb1_len, n1_len, cb2_len, i; uint32_t *data32, *swap32; - uint8_t *data8; - int diff; mutex_lock(&pool->pool_lock); @@ -4529,7 +4553,9 @@ static void gen_stratum_work(struct pool *pool, struct work *work) strcat(header, "00000000"); /* nonce */ strcat(header, "000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000"); - diff = pool->swork.diff; + /* Store the stratum work diff to check it still matches the pool's + * stratum diff when submitting shares */ + work->sdiff = pool->swork.diff; /* Copy parameters required for share submission */ sprintf(work->job_id, "%s", pool->swork.job_id); @@ -4552,25 +4578,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work) if (unlikely(!hex2bin(work->hash1, hash1, 64))) quit(1, "Failed to convert hash1 in gen_stratum_work"); - /* Scale to any diff by setting number of bits according to diff */ - hex2bin(rtarget, "00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 32); - data8 = (uint8_t *)(rtarget + 4); - for (i = 1, j = 0; i < diff; i++, j++) { - int byte = j / 8; - int bit = j % 8; - - data8[byte] &= ~(128 >> bit); - } - swab256(target, rtarget); - if (opt_debug) { - char *htarget = bin2hex(target, 32); - - if (likely(htarget)) { - applog(LOG_DEBUG, "Generated target %s", htarget); - free(htarget); - } - } - memcpy(work->target, target, 256); + set_work_target(work, work->sdiff); work->pool = pool; work->stratum = true; @@ -4579,7 +4587,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work) work->longpoll = false; work->getwork_mode = GETWORK_MODE_STRATUM; work->work_block = work_block; - calc_diff(work, diff); + calc_diff(work, work->sdiff); gettimeofday(&work->tv_staged, NULL); } @@ -4698,7 +4706,7 @@ err_out: return false; } -static bool hashtest(struct thr_info *thr, const struct work *work) +static bool hashtest(struct thr_info *thr, struct work *work) { uint32_t *data32 = (uint32_t *)(work->data); unsigned char swap[128]; @@ -4706,7 +4714,8 @@ static bool hashtest(struct thr_info *thr, const struct work *work) unsigned char hash1[32]; unsigned char hash2[32]; uint32_t *hash2_32 = (uint32_t *)hash2; - int i; + struct pool *pool = work->pool; + int i, diff; for (i = 0; i < 80 / 4; i++) swap32[i] = swab32(data32[i]); @@ -4727,6 +4736,17 @@ static bool hashtest(struct thr_info *thr, const struct work *work) return false; } + if (work->stratum) { + mutex_lock(&pool->pool_lock); + diff = pool->swork.diff; + mutex_unlock(&pool->pool_lock); + + if (unlikely(work->sdiff != diff)) { + applog(LOG_DEBUG, "Share needs retargetting to match pool"); + set_work_target(work, diff); + } + } + bool test = fulltest(work->hash, work->target); if (!test) applog(LOG_INFO, "Share below target"); diff --git a/miner.h b/miner.h index 78565f77..181a7e0a 100644 --- a/miner.h +++ b/miner.h @@ -901,6 +901,7 @@ struct work { char job_id[64]; char nonce2[64]; char ntime[16]; + int sdiff; unsigned int work_block; int id; From 3cb373d6929685768501722f453ae70df2984959 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 3 Oct 2012 12:01:29 +1000 Subject: [PATCH 086/160] Change notify message to info level to avoid spamming repeatedly when a pool is down. --- util.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/util.c b/util.c index 0afd6fb8..c0c85e81 100644 --- a/util.c +++ b/util.c @@ -1249,29 +1249,29 @@ bool initiate_stratum(struct pool *pool) notify_val = json_array_get(res_val, 0); if (!notify_val || json_is_null(notify_val)) { - applog(LOG_WARNING, "Failed to parse notify_val in initiate_stratum"); + applog(LOG_INFO, "Failed to parse notify_val in initiate_stratum"); goto out; } buf = __json_array_string(notify_val, 0); if (!buf || strcasecmp(buf, "mining.notify")) { - applog(LOG_WARNING, "Failed to get mining notify in initiate_stratum"); + applog(LOG_INFO, "Failed to get mining notify in initiate_stratum"); goto out; } pool->subscription = json_array_string(notify_val, 1); if (!pool->subscription) { - applog(LOG_WARNING, "Failed to get a subscription in initiate_stratum"); + applog(LOG_INFO, "Failed to get a subscription in initiate_stratum"); goto out; } pool->nonce1 = json_array_string(res_val, 1); if (!pool->nonce1) { - applog(LOG_WARNING, "Failed to get nonce1 in initiate_stratum"); + applog(LOG_INFO, "Failed to get nonce1 in initiate_stratum"); goto out; } pool->n2size = json_integer_value(json_array_get(res_val, 2)); if (!pool->n2size) { - applog(LOG_WARNING, "Failed to get n2size in initiate_stratum"); + applog(LOG_INFO, "Failed to get n2size in initiate_stratum"); goto out; } From 9698858abc134a5dadda33b21780e35443d4f74f Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 3 Oct 2012 18:19:31 +1000 Subject: [PATCH 087/160] Remove the sshare hash entry if we failed to send it. --- cgminer.c | 7 ++++++- util.c | 27 +++++++++++++++++++-------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/cgminer.c b/cgminer.c index a78b1a21..49693158 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2767,7 +2767,12 @@ static void *submit_work_thread(void *userdata) applog(LOG_INFO, "Submitting share %08lx to pool %d", (unsigned long)(hash32[6]), pool->pool_no); - stratum_send(pool, s, strlen(s)); + if (unlikely(!stratum_send(pool, s, strlen(s)))) { + mutex_lock(&sshare_lock); + HASH_DEL(stratum_shares, sshare); + mutex_unlock(&sshare_lock); + free(sshare); + } goto out; } diff --git a/util.c b/util.c index c0c85e81..9b6677be 100644 --- a/util.c +++ b/util.c @@ -1189,9 +1189,10 @@ out: bool initiate_stratum(struct pool *pool) { json_t *val = NULL, *res_val, *err_val, *notify_val; + bool ret = false, notify = false; char *s, *buf, *sret = NULL; json_error_t err; - bool ret = false; + int i, arr_size; if (pool->stratum_active) return true; @@ -1232,7 +1233,8 @@ bool initiate_stratum(struct pool *pool) err_val = json_object_get(val, "error"); if (!res_val || json_is_null(res_val) || - (err_val && !json_is_null(err_val))) { + (err_val && !json_is_null(err_val)) || + !json_is_array(res_val)) { char *ss; if (err_val) @@ -1247,17 +1249,26 @@ bool initiate_stratum(struct pool *pool) goto out; } - notify_val = json_array_get(res_val, 0); - if (!notify_val || json_is_null(notify_val)) { - applog(LOG_INFO, "Failed to parse notify_val in initiate_stratum"); - goto out; + arr_size = json_array_size(res_val); + for (i = 0; i < arr_size; i++) { + notify_val = json_array_get(res_val, i); + if (!notify_val || json_is_null(notify_val)) { + applog(LOG_INFO, "Failed to parse notify_val in initiate_stratum"); + goto out; + } + + buf = __json_array_string(notify_val, 0); + if (buf && !strcasecmp(buf, "mining.notify")) { + notify = true; + break; + } } - buf = __json_array_string(notify_val, 0); - if (!buf || strcasecmp(buf, "mining.notify")) { + if (!notify) { applog(LOG_INFO, "Failed to get mining notify in initiate_stratum"); goto out; } + pool->subscription = json_array_string(notify_val, 1); if (!pool->subscription) { applog(LOG_INFO, "Failed to get a subscription in initiate_stratum"); From 2fae906440cef290d4ffe73899a2c139c197f326 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 3 Oct 2012 21:10:30 +1000 Subject: [PATCH 088/160] Don't try to parse unneeded parameters in response to mining.subscribe. --- miner.h | 1 - util.c | 40 ++++++---------------------------------- 2 files changed, 6 insertions(+), 35 deletions(-) diff --git a/miner.h b/miner.h index 181a7e0a..501badf5 100644 --- a/miner.h +++ b/miner.h @@ -850,7 +850,6 @@ struct pool { SOCKETTYPE sock; struct sockaddr_in *server, client; char *sockaddr_url; /* stripped url used for sockaddr */ - char *subscription; char *nonce1; uint32_t nonce2; int n2size; diff --git a/util.c b/util.c index 9b6677be..6912531f 100644 --- a/util.c +++ b/util.c @@ -1188,11 +1188,10 @@ out: bool initiate_stratum(struct pool *pool) { - json_t *val = NULL, *res_val, *err_val, *notify_val; - bool ret = false, notify = false; - char *s, *buf, *sret = NULL; + json_t *val = NULL, *res_val, *err_val; + char *s, *sret = NULL; json_error_t err; - int i, arr_size; + bool ret = false; if (pool->stratum_active) return true; @@ -1233,8 +1232,7 @@ bool initiate_stratum(struct pool *pool) err_val = json_object_get(val, "error"); if (!res_val || json_is_null(res_val) || - (err_val && !json_is_null(err_val)) || - !json_is_array(res_val)) { + (err_val && !json_is_null(err_val))) { char *ss; if (err_val) @@ -1249,32 +1247,6 @@ bool initiate_stratum(struct pool *pool) goto out; } - arr_size = json_array_size(res_val); - for (i = 0; i < arr_size; i++) { - notify_val = json_array_get(res_val, i); - if (!notify_val || json_is_null(notify_val)) { - applog(LOG_INFO, "Failed to parse notify_val in initiate_stratum"); - goto out; - } - - buf = __json_array_string(notify_val, 0); - if (buf && !strcasecmp(buf, "mining.notify")) { - notify = true; - break; - } - } - - if (!notify) { - applog(LOG_INFO, "Failed to get mining notify in initiate_stratum"); - goto out; - } - - pool->subscription = json_array_string(notify_val, 1); - if (!pool->subscription) { - applog(LOG_INFO, "Failed to get a subscription in initiate_stratum"); - goto out; - } - pool->nonce1 = json_array_string(res_val, 1); if (!pool->nonce1) { applog(LOG_INFO, "Failed to get nonce1 in initiate_stratum"); @@ -1296,8 +1268,8 @@ out: pool->stratum_active = true; pool->swork.diff = 1; if (opt_protocol) { - applog(LOG_DEBUG, "Pool %d confirmed mining.notify with subscription %s extranonce1 %s extran2size %d", - pool->pool_no, pool->subscription, pool->nonce1, pool->n2size); + applog(LOG_DEBUG, "Pool %d confirmed mining.subscribe with extranonce1 %s extran2size %d", + pool->pool_no, pool->nonce1, pool->n2size); } } else CLOSESOCKET(pool->sock); From 512d2440948003555278f900eb15d6ce760fddfc Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 4 Oct 2012 08:52:56 +1000 Subject: [PATCH 089/160] Pass json error value to share result function to be able to parse reject reason in stratum. --- cgminer.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/cgminer.c b/cgminer.c index 49693158..c752517d 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1810,8 +1810,8 @@ static void reject_pool(struct pool *pool) * rejected values but the chance of two submits completing at the * same time is zero so there is no point adding extra locking */ static void -share_result(json_t *val, json_t *res, const struct work *work, char *hashshow, - bool resubmit, char *worktime) +share_result(json_t *val, json_t *res, json_t *err, const struct work *work, + char *hashshow, bool resubmit, char *worktime) { struct pool *pool = work->pool; struct cgpu_info *cgpu = thr_info[work->thr_id].cgpu; @@ -1917,7 +1917,7 @@ share_result(json_t *val, json_t *res, const struct work *work, char *hashshow, static bool submit_upstream_work(const struct work *work, CURL *curl, bool resubmit) { char *hexstr = NULL; - json_t *val, *res; + json_t *val, *res, *err; char s[345], sd[345]; bool rc = false; int thr_id = work->thr_id; @@ -1968,6 +1968,7 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub applog(LOG_WARNING, "Pool %d communication resumed, submitting work", pool->pool_no); res = json_object_get(val, "result"); + err = json_object_get(val, "error"); if (!QUIET) { hash32 = (uint32_t *)(work->hash); @@ -2022,7 +2023,7 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub } } - share_result(val, res, work, hashshow, resubmit, worktime); + share_result(val, res, err, work, hashshow, resubmit, worktime); cgpu->utility = cgpu->accepted / total_secs * 60; @@ -4048,7 +4049,7 @@ out_unlock: } } -static void stratum_share_result(json_t *val, json_t *res_val, +static void stratum_share_result(json_t *val, json_t *res_val, json_t *err_val, struct stratum_share *sshare) { struct work *work = &sshare->work; @@ -4060,7 +4061,7 @@ static void stratum_share_result(json_t *val, json_t *res_val, intdiff = round(work->work_difficulty); sprintf(hashshow, "%08lx Diff %d%s", (unsigned long)(hash32[6]), intdiff, work->block? " BLOCK!" : ""); - share_result(val, res_val, work, hashshow, false, ""); + share_result(val, res_val, err_val, work, hashshow, false, ""); } /* Parses stratum json responses and tries to find the id that the request @@ -4112,7 +4113,7 @@ static bool parse_stratum_response(char *s) applog(LOG_NOTICE, "Rejected untracked stratum share"); goto out; } - stratum_share_result(val, res_val, sshare); + stratum_share_result(val, res_val, err_val, sshare); free(sshare); ret = true; From b4450bb8525f648642c2f6a2d085eb07278fccd4 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 4 Oct 2012 09:17:28 +1000 Subject: [PATCH 090/160] Parse the reject reason where possible from stratum share submission. --- cgminer.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/cgminer.c b/cgminer.c index c752517d..f5ba3856 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1868,6 +1868,7 @@ share_result(json_t *val, json_t *res, json_t *err, const struct work *work, char disposition[36] = "reject"; char reason[32]; + strcpy(reason, ""); if (total_pools > 1) sprintf(where, "pool %d", work->pool->pool_no); else @@ -1885,8 +1886,15 @@ share_result(json_t *val, json_t *res, json_t *err, const struct work *work, reason[reasonLen + 2] = ')'; reason[reasonLen + 3] = '\0'; memcpy(disposition + 7, reasontmp, reasonLen); disposition[6] = ':'; disposition[reasonLen + 7] = '\0'; - } else - strcpy(reason, ""); + } else if (work->stratum && err && json_is_array(err)) { + json_t *reason_val = json_array_get(err, 1); + char *reason_str; + + if (reason_val && json_is_string(reason_val)) { + reason_str = (char *)json_string_value(reason_val); + snprintf(reason, 31, "(%s)", reason_str); + } + } applog(LOG_NOTICE, "Rejected %s %s %d %s%s %s%s", hashshow, cgpu->api->name, cgpu->device_id, where, reason, resubmit ? "(resubmit)" : "", worktime); @@ -4084,8 +4092,7 @@ static bool parse_stratum_response(char *s) err_val = json_object_get(val, "error"); id_val = json_object_get(val, "id"); - if ((!res_val || !id_val) || (json_is_null(res_val) || json_is_null(id_val)) || - (err_val && !json_is_null(err_val) && !id_val)) { + if (json_is_null(id_val) || !id_val) { char *ss; if (err_val) From 3c85498d5722641fe59abd10d2e31d693accd76e Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 4 Oct 2012 09:38:05 +1000 Subject: [PATCH 091/160] Add space to reject reason. --- cgminer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index f5ba3856..b5d7402e 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1892,7 +1892,7 @@ share_result(json_t *val, json_t *res, json_t *err, const struct work *work, if (reason_val && json_is_string(reason_val)) { reason_str = (char *)json_string_value(reason_val); - snprintf(reason, 31, "(%s)", reason_str); + snprintf(reason, 31, " (%s)", reason_str); } } From c113534feb93979b86412c7b00a9e524a26c4897 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 4 Oct 2012 15:35:28 +1000 Subject: [PATCH 092/160] Begin support for mingw stratum build. Conflicts: configure.ac --- api.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 1 + driver-icarus.c | 2 ++ logging.c | 2 ++ miner.h | 13 +++++++++ util.c | 3 +- util.h | 75 +------------------------------------------------ 7 files changed, 95 insertions(+), 75 deletions(-) diff --git a/api.c b/api.c index f8171e0a..f81eced4 100644 --- a/api.c +++ b/api.c @@ -44,6 +44,80 @@ // However lots of PGA's may mean more #define QUEUE 100 +#if defined WIN32 +static char WSAbuf[1024]; + +struct WSAERRORS { + int id; + char *code; +} WSAErrors[] = { + { 0, "No error" }, + { WSAEINTR, "Interrupted system call" }, + { WSAEBADF, "Bad file number" }, + { WSAEACCES, "Permission denied" }, + { WSAEFAULT, "Bad address" }, + { WSAEINVAL, "Invalid argument" }, + { WSAEMFILE, "Too many open sockets" }, + { WSAEWOULDBLOCK, "Operation would block" }, + { WSAEINPROGRESS, "Operation now in progress" }, + { WSAEALREADY, "Operation already in progress" }, + { WSAENOTSOCK, "Socket operation on non-socket" }, + { WSAEDESTADDRREQ, "Destination address required" }, + { WSAEMSGSIZE, "Message too long" }, + { WSAEPROTOTYPE, "Protocol wrong type for socket" }, + { WSAENOPROTOOPT, "Bad protocol option" }, + { WSAEPROTONOSUPPORT, "Protocol not supported" }, + { WSAESOCKTNOSUPPORT, "Socket type not supported" }, + { WSAEOPNOTSUPP, "Operation not supported on socket" }, + { WSAEPFNOSUPPORT, "Protocol family not supported" }, + { WSAEAFNOSUPPORT, "Address family not supported" }, + { WSAEADDRINUSE, "Address already in use" }, + { WSAEADDRNOTAVAIL, "Can't assign requested address" }, + { WSAENETDOWN, "Network is down" }, + { WSAENETUNREACH, "Network is unreachable" }, + { WSAENETRESET, "Net connection reset" }, + { WSAECONNABORTED, "Software caused connection abort" }, + { WSAECONNRESET, "Connection reset by peer" }, + { WSAENOBUFS, "No buffer space available" }, + { WSAEISCONN, "Socket is already connected" }, + { WSAENOTCONN, "Socket is not connected" }, + { WSAESHUTDOWN, "Can't send after socket shutdown" }, + { WSAETOOMANYREFS, "Too many references, can't splice" }, + { WSAETIMEDOUT, "Connection timed out" }, + { WSAECONNREFUSED, "Connection refused" }, + { WSAELOOP, "Too many levels of symbolic links" }, + { WSAENAMETOOLONG, "File name too long" }, + { WSAEHOSTDOWN, "Host is down" }, + { WSAEHOSTUNREACH, "No route to host" }, + { WSAENOTEMPTY, "Directory not empty" }, + { WSAEPROCLIM, "Too many processes" }, + { WSAEUSERS, "Too many users" }, + { WSAEDQUOT, "Disc quota exceeded" }, + { WSAESTALE, "Stale NFS file handle" }, + { WSAEREMOTE, "Too many levels of remote in path" }, + { WSASYSNOTREADY, "Network system is unavailable" }, + { WSAVERNOTSUPPORTED, "Winsock version out of range" }, + { WSANOTINITIALISED, "WSAStartup not yet called" }, + { WSAEDISCON, "Graceful shutdown in progress" }, + { WSAHOST_NOT_FOUND, "Host not found" }, + { WSANO_DATA, "No host data of that type was found" }, + { -1, "Unknown error code" } +}; + +char *WSAErrorMsg(void) { + int i; + int id = WSAGetLastError(); + + /* Assume none of them are actually -1 */ + for (i = 0; WSAErrors[i].id != -1; i++) + if (WSAErrors[i].id == id) + break; + + sprintf(WSAbuf, "Socket Error: (%d) %s", id, WSAErrors[i].code); + + return &(WSAbuf[0]); +} +#endif static char *io_buffer = NULL; static char *msg_buffer = NULL; static SOCKETTYPE sock = INVSOCK; diff --git a/configure.ac b/configure.ac index fe618e02..f9fc107a 100644 --- a/configure.ac +++ b/configure.ac @@ -92,6 +92,7 @@ case $target in PTHREAD_FLAGS="" DLOPEN_FLAGS="" WS2_LIBS="-lws2_32" + AC_DEFINE([_WIN32_WINNT], [0x0501], "WinNT version for XP+ support") ;; powerpc-*-darwin*) CFLAGS="$CFLAGS -faltivec" diff --git a/driver-icarus.c b/driver-icarus.c index 4214c31b..2cc2a454 100644 --- a/driver-icarus.c +++ b/driver-icarus.c @@ -29,6 +29,8 @@ * nonce range is completely calculated. */ +#include "config.h" + #include #include #include diff --git a/logging.c b/logging.c index 47d1970d..afc70089 100644 --- a/logging.c +++ b/logging.c @@ -7,6 +7,8 @@ * any later version. See COPYING for more details. */ +#include "config.h" + #include #include "logging.h" diff --git a/miner.h b/miner.h index 501badf5..7bf1309f 100644 --- a/miner.h +++ b/miner.h @@ -52,6 +52,19 @@ void *alloca (size_t); # endif #endif +#ifdef __MINGW32__ +#include +#include +static inline int fsync (int fd) +{ + return (FlushFileBuffers ((HANDLE) _get_osfhandle (fd))) ? 0 : -1; +} + +#ifndef MSG_DONTWAIT +# define MSG_DONTWAIT 0x1000000 +#endif +#endif /* __MINGW32__ */ + #if defined (__linux) #ifndef LINUX #define LINUX diff --git a/util.c b/util.c index 6912531f..b11c1165 100644 --- a/util.c +++ b/util.c @@ -26,11 +26,12 @@ # include # include # include +# include #else # include # include +# include #endif -#include #include "miner.h" #include "elist.h" diff --git a/util.h b/util.h index 2560552a..3829c07f 100644 --- a/util.h +++ b/util.h @@ -24,80 +24,7 @@ #define INVINETADDR INADDR_NONE #define CLOSESOCKET closesocket - static char WSAbuf[1024]; - - struct WSAERRORS { - int id; - char *code; - } WSAErrors[] = { - { 0, "No error" }, - { WSAEINTR, "Interrupted system call" }, - { WSAEBADF, "Bad file number" }, - { WSAEACCES, "Permission denied" }, - { WSAEFAULT, "Bad address" }, - { WSAEINVAL, "Invalid argument" }, - { WSAEMFILE, "Too many open sockets" }, - { WSAEWOULDBLOCK, "Operation would block" }, - { WSAEINPROGRESS, "Operation now in progress" }, - { WSAEALREADY, "Operation already in progress" }, - { WSAENOTSOCK, "Socket operation on non-socket" }, - { WSAEDESTADDRREQ, "Destination address required" }, - { WSAEMSGSIZE, "Message too long" }, - { WSAEPROTOTYPE, "Protocol wrong type for socket" }, - { WSAENOPROTOOPT, "Bad protocol option" }, - { WSAEPROTONOSUPPORT, "Protocol not supported" }, - { WSAESOCKTNOSUPPORT, "Socket type not supported" }, - { WSAEOPNOTSUPP, "Operation not supported on socket" }, - { WSAEPFNOSUPPORT, "Protocol family not supported" }, - { WSAEAFNOSUPPORT, "Address family not supported" }, - { WSAEADDRINUSE, "Address already in use" }, - { WSAEADDRNOTAVAIL, "Can't assign requested address" }, - { WSAENETDOWN, "Network is down" }, - { WSAENETUNREACH, "Network is unreachable" }, - { WSAENETRESET, "Net connection reset" }, - { WSAECONNABORTED, "Software caused connection abort" }, - { WSAECONNRESET, "Connection reset by peer" }, - { WSAENOBUFS, "No buffer space available" }, - { WSAEISCONN, "Socket is already connected" }, - { WSAENOTCONN, "Socket is not connected" }, - { WSAESHUTDOWN, "Can't send after socket shutdown" }, - { WSAETOOMANYREFS, "Too many references, can't splice" }, - { WSAETIMEDOUT, "Connection timed out" }, - { WSAECONNREFUSED, "Connection refused" }, - { WSAELOOP, "Too many levels of symbolic links" }, - { WSAENAMETOOLONG, "File name too long" }, - { WSAEHOSTDOWN, "Host is down" }, - { WSAEHOSTUNREACH, "No route to host" }, - { WSAENOTEMPTY, "Directory not empty" }, - { WSAEPROCLIM, "Too many processes" }, - { WSAEUSERS, "Too many users" }, - { WSAEDQUOT, "Disc quota exceeded" }, - { WSAESTALE, "Stale NFS file handle" }, - { WSAEREMOTE, "Too many levels of remote in path" }, - { WSASYSNOTREADY, "Network system is unavailable" }, - { WSAVERNOTSUPPORTED, "Winsock version out of range" }, - { WSANOTINITIALISED, "WSAStartup not yet called" }, - { WSAEDISCON, "Graceful shutdown in progress" }, - { WSAHOST_NOT_FOUND, "Host not found" }, - { WSANO_DATA, "No host data of that type was found" }, - { -1, "Unknown error code" } - }; - - static char *WSAErrorMsg() - { - int i; - int id = WSAGetLastError(); - - /* Assume none of them are actually -1 */ - for (i = 0; WSAErrors[i].id != -1; i++) - if (WSAErrors[i].id == id) - break; - - sprintf(WSAbuf, "Socket Error: (%d) %s", id, WSAErrors[i].code); - - return &(WSAbuf[0]); - } - + extern char *WSAErrorMsg(void); #define SOCKERRMSG WSAErrorMsg() #ifndef SHUT_RDWR From 77c5a006aa0aa297e000f488c31bff2cb022a9e8 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 4 Oct 2012 21:00:32 +1000 Subject: [PATCH 093/160] Alloca is unreliable on windows so use static arrays in util.c stratum code. --- util.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/util.c b/util.c index b11c1165..713776e6 100644 --- a/util.c +++ b/util.c @@ -811,7 +811,7 @@ double tdiff(struct timeval *end, struct timeval *start) bool extract_sockaddr(struct pool *pool, char *url) { char *url_begin, *url_end, *port_start = NULL; - char *url_address, *port; + char url_address[256], port[6]; struct addrinfo hints, *res; int url_len, port_len = 0; @@ -833,14 +833,11 @@ bool extract_sockaddr(struct pool *pool, char *url) if (url_len < 1) return false; - url_address = alloca(url_len + 1); sprintf(url_address, "%.*s", url_len, url_begin); if (port_len) { - port = alloca(port_len + 1); sprintf(port, "%.*s", port_len, port_start); } else { - port = alloca(4); strcpy(port, "80"); } @@ -889,10 +886,11 @@ out_unlock: } #define RECVSIZE 8191 +#define RBUFSIZE (RECVSIZE + 1) static void clear_sock(SOCKETTYPE sock) { - char *s = alloca(RECVSIZE); + char s[RBUFSIZE]; recv(sock, s, RECVSIZE, MSG_DONTWAIT); } @@ -919,10 +917,9 @@ static bool sock_full(SOCKETTYPE sock, bool wait) * from the socket and returns that as a malloced char */ char *recv_line(SOCKETTYPE sock) { - char *sret = NULL, *s, c; + char *sret = NULL, s[RBUFSIZE], c; ssize_t offset = 0; - s = alloca(RECVSIZE + 1); if (SOCKETFAIL(recv(sock, s, RECVSIZE, MSG_PEEK))) { applog(LOG_DEBUG, "Failed to recv sock in recv_line"); goto out; @@ -1133,11 +1130,10 @@ out: bool auth_stratum(struct pool *pool) { json_t *val = NULL, *res_val, *err_val; - char *s, *sret = NULL; + char s[RBUFSIZE], *sret = NULL; json_error_t err; bool ret = false; - s = alloca(RECVSIZE + 1); sprintf(s, "{\"id\": %d, \"method\": \"mining.authorize\", \"params\": [\"%s\", \"%s\"]}", swork_id++, pool->rpc_user, pool->rpc_pass); @@ -1190,14 +1186,13 @@ out: bool initiate_stratum(struct pool *pool) { json_t *val = NULL, *res_val, *err_val; - char *s, *sret = NULL; + char s[RBUFSIZE], *sret = NULL; json_error_t err; bool ret = false; if (pool->stratum_active) return true; - s = alloca(RECVSIZE + 1); sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": []}", swork_id++); pool->sock = socket(AF_INET, SOCK_STREAM, 0); From deb0a9b644b4918c954e0a7abe325d25a4fc5b5e Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 4 Oct 2012 23:18:33 +1000 Subject: [PATCH 094/160] Windows doesn't work with MSG_PEEK on recv so move to a continuously updating buffer for incoming messages. --- cgminer.c | 2 +- miner.h | 4 ++++ util.c | 66 ++++++++++++++++++++++++++++++++++--------------------- util.h | 2 +- 4 files changed, 47 insertions(+), 27 deletions(-) diff --git a/cgminer.c b/cgminer.c index b5d7402e..36adc5b5 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4161,7 +4161,7 @@ static void *stratum_thread(void *userdata) sleep(5); } } - s = recv_line(pool->sock); + s = recv_line(pool); if (unlikely(!s)) continue; if (!parse_method(pool, s) && !parse_stratum_response(s)) diff --git a/miner.h b/miner.h index 7bf1309f..42c19351 100644 --- a/miner.h +++ b/miner.h @@ -795,6 +795,9 @@ struct stratum_work { int diff; }; +#define RECVSIZE 8191 +#define RBUFSIZE (RECVSIZE + 1) + struct pool { int pool_no; int prio; @@ -861,6 +864,7 @@ struct pool { /* Stratum variables */ char *stratum_url; SOCKETTYPE sock; + char sockbuf[RBUFSIZE]; struct sockaddr_in *server, client; char *sockaddr_url; /* stripped url used for sockaddr */ char *nonce1; diff --git a/util.c b/util.c index 713776e6..f1d4defd 100644 --- a/util.c +++ b/util.c @@ -888,19 +888,24 @@ out_unlock: #define RECVSIZE 8191 #define RBUFSIZE (RECVSIZE + 1) -static void clear_sock(SOCKETTYPE sock) +static void clear_sock(struct pool *pool) { - char s[RBUFSIZE]; + SOCKETTYPE sock = pool->sock; - recv(sock, s, RECVSIZE, MSG_DONTWAIT); + recv(sock, pool->sockbuf, RECVSIZE, MSG_DONTWAIT); + strcpy(pool->sockbuf, ""); } /* Check to see if Santa's been good to you */ -static bool sock_full(SOCKETTYPE sock, bool wait) +static bool sock_full(struct pool *pool, bool wait) { + SOCKETTYPE sock = pool->sock; struct timeval timeout; fd_set rd; + if (strlen(pool->sockbuf)) + return true; + FD_ZERO(&rd); FD_SET(sock, &rd); timeout.tv_usec = 0; @@ -915,30 +920,41 @@ static bool sock_full(SOCKETTYPE sock, bool wait) /* Peeks at a socket to find the first end of line and then reads just that * from the socket and returns that as a malloced char */ -char *recv_line(SOCKETTYPE sock) +char *recv_line(struct pool *pool) { - char *sret = NULL, s[RBUFSIZE], c; - ssize_t offset = 0; + SOCKETTYPE sock = pool->sock; + ssize_t len, buflen; + char *tok, *sret = NULL; - if (SOCKETFAIL(recv(sock, s, RECVSIZE, MSG_PEEK))) { - applog(LOG_DEBUG, "Failed to recv sock in recv_line"); - goto out; + if (!strstr(pool->sockbuf, "\n")) { + char s[RBUFSIZE]; + + memset(s, 0, RBUFSIZE); + if (SOCKETFAIL(recv(sock, s, RECVSIZE, 0))) { + applog(LOG_DEBUG, "Failed to recv sock in recv_line"); + goto out; + } + strcat(pool->sockbuf, s); } - sret = strtok(s, "\n"); - if (!sret) { + + buflen = strlen(pool->sockbuf); + tok = strtok(pool->sockbuf, "\n"); + if (!tok) { applog(LOG_DEBUG, "Failed to parse a \\n terminated string in recv_line"); goto out; } + sret = strdup(tok); + len = strlen(sret); - do { - read(sock, &c, 1); - memcpy(s + offset++, &c, 1); - } while (strncmp(&c, "\n", 1)); - sret = strdup(s); - strcpy(sret + offset - 1, "\0"); + /* Copy what's left in the buffer after the \n, including the + * terminating \0 */ + if (buflen > len + 1) + memmove(pool->sockbuf, pool->sockbuf + len + 1, buflen - len + 1); + else + strcpy(pool->sockbuf, ""); out: if (!sret) - clear_sock(sock); + clear_sock(pool); else if (opt_protocol) applog(LOG_DEBUG, "RECVD: %s", sret); return sret; @@ -1138,10 +1154,10 @@ bool auth_stratum(struct pool *pool) swork_id++, pool->rpc_user, pool->rpc_pass); /* Parse all data prior sending auth request */ - while (sock_full(pool->sock, false)) { - sret = recv_line(pool->sock); + while (sock_full(pool, false)) { + sret = recv_line(pool); if (!parse_method(pool, sret)) { - clear_sock(pool->sock); + clear_sock(pool); applog(LOG_WARNING, "Failed to parse stratum buffer"); free(sret); return ret; @@ -1152,7 +1168,7 @@ bool auth_stratum(struct pool *pool) if (!stratum_send(pool, s, strlen(s))) goto out; - sret = recv_line(pool->sock); + sret = recv_line(pool); if (!sret) goto out; val = JSON_LOADS(sret, &err); @@ -1208,12 +1224,12 @@ bool initiate_stratum(struct pool *pool) goto out; } - if (!sock_full(pool->sock, true)) { + if (!sock_full(pool, true)) { applog(LOG_DEBUG, "Timed out waiting for response in initiate_stratum"); goto out; } - sret = recv_line(pool->sock); + sret = recv_line(pool); if (!sret) goto out; diff --git a/util.h b/util.h index 3829c07f..fb520ca7 100644 --- a/util.h +++ b/util.h @@ -44,7 +44,7 @@ struct pool; bool stratum_send(struct pool *pool, char *s, ssize_t len); -char *recv_line(SOCKETTYPE sock); +char *recv_line(struct pool *pool); bool parse_method(struct pool *pool, char *s); bool extract_sockaddr(struct pool *pool, char *url); bool auth_stratum(struct pool *pool); From 51c499a5ae07122d146a7be2d35ea92df3093145 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 5 Oct 2012 00:08:49 +1000 Subject: [PATCH 095/160] Stratum does not currently have any proxy support so do not try to switch to stratum if a proxy has been specified. --- cgminer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index 36adc5b5..482907cb 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4241,8 +4241,9 @@ retry_stratum: gettimeofday(&tv_getwork_reply, NULL); /* Detect if a http getwork pool has an X-Stratum header at startup, - * and if so, switch to that in preference to getwork */ - if (unlikely(pool->stratum_url)) { + * and if so, switch to that in preference to getwork. Currently no + * proxy support so don't try to switch if a proxy is in use. */ + if (unlikely(pool->stratum_url && !pool->rpc_proxy)) { applog(LOG_NOTICE, "Switching pool %d %s to %s", pool->pool_no, pool->rpc_url, pool->stratum_url); pool->has_stratum = true; pool->rpc_url = pool->stratum_url; From 591c43347770d8a7ed4cdb9f5551dff9d1d14e39 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 5 Oct 2012 09:41:23 +1000 Subject: [PATCH 096/160] Make detect stratum fail if a proxy has been set up. --- cgminer.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cgminer.c b/cgminer.c index 482907cb..c2d19b27 100644 --- a/cgminer.c +++ b/cgminer.c @@ -562,6 +562,12 @@ static char *set_rr(enum pool_strategy *strategy) * stratum+tcp or by detecting a stratum server response */ bool detect_stratum(struct pool *pool, char *url) { + if (pool->rpc_proxy) { + if (!strncasecmp(url, "stratum+tcp://", 14)) + applog(LOG_WARNING, "Cannot use a stratum server with a proxy"); + return false; + } + if (!extract_sockaddr(pool, url)) return false; From a8d693029a0721fc74cf80231b748810e54b30e7 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 5 Oct 2012 12:37:29 +1000 Subject: [PATCH 097/160] Move stratum sockets to curl infrastructure with locking around send+recv to begin support for proxies and ssl. --- cgminer.c | 10 ++---- configure.ac | 3 +- miner.h | 3 ++ util.c | 88 +++++++++++++++++++++++++++++++++++++--------------- util.h | 2 +- 5 files changed, 71 insertions(+), 35 deletions(-) diff --git a/cgminer.c b/cgminer.c index c2d19b27..aa71c466 100644 --- a/cgminer.c +++ b/cgminer.c @@ -432,6 +432,8 @@ struct pool *add_pool(void) quit(1, "Failed to pthread_mutex_init in add_pool"); 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"); INIT_LIST_HEAD(&pool->curlring); /* Make sure the pool doesn't think we've been idle since time 0 */ @@ -562,12 +564,6 @@ static char *set_rr(enum pool_strategy *strategy) * stratum+tcp or by detecting a stratum server response */ bool detect_stratum(struct pool *pool, char *url) { - if (pool->rpc_proxy) { - if (!strncasecmp(url, "stratum+tcp://", 14)) - applog(LOG_WARNING, "Cannot use a stratum server with a proxy"); - return false; - } - if (!extract_sockaddr(pool, url)) return false; @@ -4249,7 +4245,7 @@ retry_stratum: /* Detect if a http getwork pool has an X-Stratum header at startup, * and if so, switch to that in preference to getwork. Currently no * proxy support so don't try to switch if a proxy is in use. */ - if (unlikely(pool->stratum_url && !pool->rpc_proxy)) { + if (unlikely(pool->stratum_url)) { applog(LOG_NOTICE, "Switching pool %d %s to %s", pool->pool_no, pool->rpc_url, pool->stratum_url); pool->has_stratum = true; pool->rpc_url = pool->stratum_url; diff --git a/configure.ac b/configure.ac index f9fc107a..55dc2c7e 100644 --- a/configure.ac +++ b/configure.ac @@ -352,8 +352,7 @@ fi PKG_PROG_PKG_CONFIG() -PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.15.6], [AC_DEFINE([CURL_HAS_SOCKOPT], [1], [Defined if version of curl supports sockopts.])], -[PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.10.1], ,[AC_MSG_ERROR([Missing required libcurl dev >= 7.10.1])])]) +PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.18.2], ,[AC_MSG_ERROR([Missing required libcurl dev >= 7.18.2])]) AC_SUBST(LIBCURL_LIBS) dnl CCAN wants to know a lot of vars. diff --git a/miner.h b/miner.h index 42c19351..0140db20 100644 --- a/miner.h +++ b/miner.h @@ -863,6 +863,8 @@ struct pool { /* Stratum variables */ char *stratum_url; + char *stratum_port; + CURL *stratum_curl; SOCKETTYPE sock; char sockbuf[RBUFSIZE]; struct sockaddr_in *server, client; @@ -875,6 +877,7 @@ struct pool { bool stratum_auth; struct stratum_work swork; pthread_t stratum_thread; + pthread_mutex_t stratum_lock; }; #define GETWORK_MODE_TESTPOOL 'T' diff --git a/util.c b/util.c index f1d4defd..7d7ca430 100644 --- a/util.c +++ b/util.c @@ -196,7 +196,6 @@ out: return ptrlen; } -#ifdef CURL_HAS_SOCKOPT int json_rpc_call_sockopt_cb(void __maybe_unused *userdata, curl_socket_t fd, curlsocktype __maybe_unused purpose) { @@ -244,7 +243,6 @@ int json_rpc_call_sockopt_cb(void __maybe_unused *userdata, curl_socket_t fd, return 0; } -#endif static void last_nettime(struct timeval *last) { @@ -319,10 +317,8 @@ json_t *json_rpc_call(CURL *curl, const char *url, curl_easy_setopt(curl, CURLOPT_USERPWD, userpass); curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); } -#ifdef CURL_HAS_SOCKOPT if (longpoll) curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, json_rpc_call_sockopt_cb); -#endif curl_easy_setopt(curl, CURLOPT_POST, 1); if (opt_protocol) @@ -835,11 +831,12 @@ bool extract_sockaddr(struct pool *pool, char *url) sprintf(url_address, "%.*s", url_len, url_begin); - if (port_len) { + if (port_len) sprintf(port, "%.*s", port_len, port_start); - } else { + else strcpy(port, "80"); - } + + pool->stratum_port = strdup(port); memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; @@ -859,8 +856,7 @@ bool extract_sockaddr(struct pool *pool, char *url) /* Send a single command across a socket, appending \n to it */ bool stratum_send(struct pool *pool, char *s, ssize_t len) { - SOCKETTYPE sock = pool->sock; - ssize_t sent = 0; + ssize_t ssent = 0; bool ret = false; if (opt_protocol) @@ -869,19 +865,21 @@ bool stratum_send(struct pool *pool, char *s, ssize_t len) strcat(s, "\n"); len++; - mutex_lock(&pool->pool_lock); + mutex_lock(&pool->stratum_lock); while (len > 0 ) { - sent = send(sock, s + sent, len, 0); - if (SOCKETFAIL(sent)) { + size_t sent = 0; + + if (curl_easy_send(pool->stratum_curl, s + ssent, len, &sent) != CURLE_OK) { + applog(LOG_DEBUG, "Failed to curl_easy_send in stratum_send"); ret = false; goto out_unlock; } - len -= sent; + ssent += sent; + len -= ssent; } ret = true; - fsync(sock); out_unlock: - mutex_unlock(&pool->pool_lock); + mutex_unlock(&pool->stratum_lock); return ret;; } @@ -922,15 +920,25 @@ static bool sock_full(struct pool *pool, bool wait) * from the socket and returns that as a malloced char */ char *recv_line(struct pool *pool) { - SOCKETTYPE sock = pool->sock; ssize_t len, buflen; char *tok, *sret = NULL; + size_t n; if (!strstr(pool->sockbuf, "\n")) { char s[RBUFSIZE]; + CURLcode rc; + if (!sock_full(pool, true)) { + applog(LOG_DEBUG, "Timed out waiting for data on sock_full"); + goto out; + } memset(s, 0, RBUFSIZE); - if (SOCKETFAIL(recv(sock, s, RECVSIZE, 0))) { + + mutex_lock(&pool->stratum_lock); + rc = curl_easy_recv(pool->stratum_curl, s, RECVSIZE, &n); + mutex_unlock(&pool->stratum_lock); + + if (rc != CURLE_OK) { applog(LOG_DEBUG, "Failed to recv sock in recv_line"); goto out; } @@ -1202,22 +1210,48 @@ out: bool initiate_stratum(struct pool *pool) { json_t *val = NULL, *res_val, *err_val; + char curl_err_str[CURL_ERROR_SIZE]; char s[RBUFSIZE], *sret = NULL; + CURL *curl = NULL; json_error_t err; bool ret = false; if (pool->stratum_active) return true; - sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": []}", swork_id++); + if (!pool->stratum_curl) { + pool->stratum_curl = curl_easy_init(); + if (unlikely(!pool->stratum_curl)) + quit(1, "Failed to curl_easy_init in initiate_stratum"); + } + curl = pool->stratum_curl; - pool->sock = socket(AF_INET, SOCK_STREAM, 0); - if (pool->sock == INVSOCK) - quit(1, "Failed to create pool socket in initiate_stratum"); - if (SOCKETFAIL(connect(pool->sock, (struct sockaddr *)pool->server, sizeof(struct sockaddr)))) { - applog(LOG_DEBUG, "Failed to connect socket to pool"); + /* Create a http url for use with curl */ + memset(s, 0, RBUFSIZE); + sprintf(s, "http://%s:%s", pool->sockaddr_url, pool->stratum_port); + + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 60); + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_err_str); + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(curl, CURLOPT_URL, s); + curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1); + curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY); + curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1); + if (pool->rpc_proxy) { + curl_easy_setopt(curl, CURLOPT_PROXY, pool->rpc_proxy); + curl_easy_setopt(curl, CURLOPT_PROXYTYPE, pool->rpc_proxytype); + } else if (opt_socks_proxy) { + curl_easy_setopt(curl, CURLOPT_PROXY, opt_socks_proxy); + curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4); + } + curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1); + if (curl_easy_perform(curl)) { + applog(LOG_ERR, "Stratum connect failed: %s", curl_err_str); goto out; } + curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, (long *)&pool->sock); + + sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": []}", swork_id++); if (!stratum_send(pool, s, strlen(s))) { applog(LOG_DEBUG, "Failed to send s in initiate_stratum"); @@ -1283,8 +1317,12 @@ out: applog(LOG_DEBUG, "Pool %d confirmed mining.subscribe with extranonce1 %s extran2size %d", pool->pool_no, pool->nonce1, pool->n2size); } - } else - CLOSESOCKET(pool->sock); + } else { + if (curl) { + curl_easy_cleanup(curl); + pool->stratum_curl = NULL; + } + } return ret; } diff --git a/util.h b/util.h index fb520ca7..aec827d4 100644 --- a/util.h +++ b/util.h @@ -7,7 +7,7 @@ #include #include - #define SOCKETTYPE int + #define SOCKETTYPE long #define SOCKETFAIL(a) ((a) < 0) #define INVSOCK -1 #define INVINETADDR -1 From fa444294bfc0b5f3aee1ea905aa0d210cfa0c21c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 5 Oct 2012 12:41:59 +1000 Subject: [PATCH 098/160] TCP Keepalive in curl is only in very recent versions and not required with regular messages on stratum anyway. --- util.c | 1 - 1 file changed, 1 deletion(-) diff --git a/util.c b/util.c index 7d7ca430..17e24280 100644 --- a/util.c +++ b/util.c @@ -1236,7 +1236,6 @@ bool initiate_stratum(struct pool *pool) curl_easy_setopt(curl, CURLOPT_URL, s); curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1); curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY); - curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1); if (pool->rpc_proxy) { curl_easy_setopt(curl, CURLOPT_PROXY, pool->rpc_proxy); curl_easy_setopt(curl, CURLOPT_PROXYTYPE, pool->rpc_proxytype); From ef63ea3151c62306e1180208990b0aa864c8231c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 5 Oct 2012 12:45:07 +1000 Subject: [PATCH 099/160] Drop stratum connect failed message to verbose level only since it's a regular probing message. --- util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util.c b/util.c index 17e24280..0fd6b54b 100644 --- a/util.c +++ b/util.c @@ -1245,7 +1245,7 @@ bool initiate_stratum(struct pool *pool) } curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1); if (curl_easy_perform(curl)) { - applog(LOG_ERR, "Stratum connect failed: %s", curl_err_str); + applog(LOG_INFO, "Stratum connect failed to pool %d: %s", pool->pool_no, curl_err_str); goto out; } curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, (long *)&pool->sock); From f0901e0a263c187c58369025d2d929c2f4c1cae2 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 5 Oct 2012 18:08:33 +1000 Subject: [PATCH 100/160] Clear work stratum strings before setting them and add them to debug output. --- cgminer.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cgminer.c b/cgminer.c index aa71c466..b5f82cb2 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4525,6 +4525,10 @@ static void gen_stratum_work(struct pool *pool, struct work *work) int len, cb1_len, n1_len, cb2_len, i; uint32_t *data32, *swap32; + memset(work->job_id, 0, 64); + memset(work->nonce2, 0, 64); + memset(work->ntime, 0, 16); + mutex_lock(&pool->pool_lock); /* Generate coinbase */ @@ -4583,6 +4587,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work) applog(LOG_DEBUG, "Generated stratum merkle %s", merkle_hash); applog(LOG_DEBUG, "Generated stratum header %s", header); + applog(LOG_DEBUG, "Work job_id %s nonce2 %s ntime %s", work->job_id, work->nonce2, work->ntime); free(merkle_hash); From c4aa8d267cd67dbdefc96923d04071e6a6ee6361 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 5 Oct 2012 19:02:10 +1000 Subject: [PATCH 101/160] Clear the buffer data before sprinting to it. --- cgminer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cgminer.c b/cgminer.c index b5f82cb2..49f9c4f9 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2772,6 +2772,7 @@ static void *submit_work_thread(void *userdata) nonce = *((uint32_t *)(work->data + 76)); noncehex = bin2hex((const unsigned char *)&nonce, 4); + memset(s, 0, 1024); sprintf(s, "{\"params\": [\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"], \"id\": %d, \"method\": \"mining.submit\"}", pool->rpc_user, work->job_id, work->nonce2, work->ntime, noncehex, sshare->id); free(noncehex); From 687fed1de9126537dbe894dc2dddb52cdd3ae2e2 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 5 Oct 2012 19:03:28 +1000 Subject: [PATCH 102/160] Use a static array for work submission data instead of stack memory. --- cgminer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 49f9c4f9..f6798560 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2758,8 +2758,8 @@ static void *submit_work_thread(void *userdata) if (work->stratum) { struct stratum_share *sshare = calloc(sizeof(struct stratum_share), 1); uint32_t *hash32 = (uint32_t *)work->hash, nonce; - char *s = alloca(1024); char *noncehex; + char s[1024]; memcpy(&sshare->work, work, sizeof(struct work)); From 8893f7ab233198baa4c6e99071d2f854e4cc6815 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 6 Oct 2012 01:13:52 +1000 Subject: [PATCH 103/160] Target should only be 32 bytes copied. --- cgminer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index f6798560..01527bcf 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4516,7 +4516,7 @@ static void set_work_target(struct work *work, int diff) free(htarget); } } - memcpy(work->target, target, 256); + memcpy(work->target, target, 32); } static void gen_stratum_work(struct pool *pool, struct work *work) From 7a01578cc56726242ec78ddf5fe0b74653a75685 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 6 Oct 2012 10:14:30 +1000 Subject: [PATCH 104/160] Only hand off to stratum from getwork if we succeed in initiating the protocol. --- cgminer.c | 23 +++++++++++++++-------- util.c | 3 ++- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/cgminer.c b/cgminer.c index 01527bcf..b40a77aa 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4206,6 +4206,18 @@ static void init_stratum_thread(struct pool *pool) static void *longpoll_thread(void *userdata); +static bool stratum_works(struct pool *pool) +{ + applog(LOG_INFO, "Testing pool %d stratum %s", pool->pool_no, pool->stratum_url); + if (!extract_sockaddr(pool, pool->stratum_url)) + return false; + + if (!initiate_stratum(pool)) + return false; + + return true; +} + static bool pool_active(struct pool *pool, bool pinging) { struct timeval tv_getwork, tv_getwork_reply; @@ -4244,18 +4256,13 @@ retry_stratum: gettimeofday(&tv_getwork_reply, NULL); /* Detect if a http getwork pool has an X-Stratum header at startup, - * and if so, switch to that in preference to getwork. Currently no - * proxy support so don't try to switch if a proxy is in use. */ - if (unlikely(pool->stratum_url)) { + * and if so, switch to that in preference to getwork if it works */ + if (pool->stratum_url && stratum_works(pool)) { applog(LOG_NOTICE, "Switching pool %d %s to %s", pool->pool_no, pool->rpc_url, pool->stratum_url); pool->has_stratum = true; - pool->rpc_url = pool->stratum_url; - /* pool->stratum_url will be set again in extract_sockaddr */ - pool->stratum_url = NULL; - extract_sockaddr(pool, pool->rpc_url); curl_easy_cleanup(curl); - goto retry_stratum; + goto retry_stratum; } if (val) { diff --git a/util.c b/util.c index 0fd6b54b..d39d1038 100644 --- a/util.c +++ b/util.c @@ -1309,7 +1309,8 @@ out: json_decref(val); if (ret) { - pool->stratum_url = pool->sockaddr_url; + if (!pool->stratum_url) + pool->stratum_url = pool->sockaddr_url; pool->stratum_active = true; pool->swork.diff = 1; if (opt_protocol) { From 0cddd1ab54921c95a219bb72278a8daa08642b85 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 6 Oct 2012 12:17:46 +1000 Subject: [PATCH 105/160] Only set the stratum auth flag once and once the stratum thread is started, use that to set/unset the stratum active flag. --- cgminer.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/cgminer.c b/cgminer.c index b40a77aa..3e190280 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4152,7 +4152,7 @@ static void *stratum_thread(void *userdata) FD_SET(pool->sock, &rd); if (select(pool->sock + 1, &rd, NULL, NULL, NULL) < 0) { - pool->stratum_active = pool->stratum_auth = false; + pool->stratum_active = false; applog(LOG_WARNING, "Stratum connection to pool %d interrupted", pool->pool_no); pool->getfail_occasions++; total_go++; @@ -4231,16 +4231,17 @@ static bool pool_active(struct pool *pool, bool pinging) /* This is the central point we activate stratum when we can */ retry_stratum: if (pool->has_stratum) { - if ((!pool->stratum_active || pinging) && !initiate_stratum(pool)) + /* We create the stratum thread for each pool just after + * successful authorisation. Once the auth flag has been set + * we never unset it and the stratum thread is responsible for + * setting/unsetting the active flag */ + if (pool->stratum_auth) + return pool->stratum_active; + if (!pool->stratum_active && !initiate_stratum(pool)) return false; - if (!pool->stratum_auth) { - if (!auth_stratum(pool)) - return false; - /* We create the stratum thread for each pool just - * after successful authorisation */ - init_stratum_thread(pool); - return true; - } + if (!auth_stratum(pool)) + return false; + init_stratum_thread(pool); return true; } From 8a32f381b48318834b647a073066a365cb3980af Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 6 Oct 2012 14:33:51 +1000 Subject: [PATCH 106/160] Use the stratum thread to detect when a stratum pool has died based on no message for 2 minutes. --- cgminer.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/cgminer.c b/cgminer.c index 3e190280..a486bac3 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4134,6 +4134,8 @@ out: return ret; } +static void pool_resus(struct pool *pool); + /* 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 @@ -4145,24 +4147,36 @@ static void *stratum_thread(void *userdata) pthread_detach(pthread_self()); while (42) { + struct timeval timeout; fd_set rd; char *s; + if (unlikely(pool->removed)) + break; + FD_ZERO(&rd); FD_SET(pool->sock, &rd); - - if (select(pool->sock + 1, &rd, NULL, NULL, NULL) < 0) { - pool->stratum_active = false; - applog(LOG_WARNING, "Stratum connection to pool %d interrupted", pool->pool_no); + timeout.tv_sec = 120; + timeout.tv_usec = 0; + + /* The protocol specifies that notify messages should be sent + * every minute so if we fail to receive any for 2 minutes we + * assume the connection has been dropped and treat this pool + * as dead */ + if (select(pool->sock + 1, &rd, NULL, NULL, &timeout) < 1) { + applog(LOG_INFO, "Stratum connection to pool %d interrupted", pool->pool_no); pool->getfail_occasions++; total_go++; + + pool_died(pool); while (!initiate_stratum(pool) || !auth_stratum(pool)) { - if (!pool->idle) - pool_died(pool); if (pool->removed) goto out; sleep(5); } + applog(LOG_INFO, "Stratum connection to pool %d resumed", pool->pool_no); + pool_resus(pool); + continue; } s = recv_line(pool); if (unlikely(!s)) @@ -4188,10 +4202,6 @@ static void *stratum_thread(void *userdata) applog(LOG_NOTICE, "Stratum from pool %d detected new block", pool->pool_no); } - if (unlikely(pool->removed)) { - CLOSESOCKET(pool->sock); - goto out; - } } out: @@ -4241,6 +4251,7 @@ retry_stratum: return false; if (!auth_stratum(pool)) return false; + pool->idle = false; init_stratum_thread(pool); return true; } @@ -4527,6 +4538,9 @@ static void set_work_target(struct work *work, int diff) memcpy(work->target, target, 32); } +/* Generates stratum based work based on the most recent notify information + * from the pool. This will keep generating work while a pool is down so we use + * other means to detect when the pool has died in stratum_thread */ static void gen_stratum_work(struct pool *pool, struct work *work) { unsigned char *coinbase, merkle_root[33], merkle_sha[65], *merkle_hash; @@ -5256,7 +5270,8 @@ static void *watchpool_thread(void __maybe_unused *userdata) if (!opt_benchmark) reap_curl(pool); - if (pool->enabled == POOL_DISABLED) + + if (pool->enabled == POOL_DISABLED || pool->has_stratum) continue; /* Test pool is idle once every minute */ From 2ff1610307d6e780c0bf33751bad4aac83c89cad Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 6 Oct 2012 14:58:26 +1000 Subject: [PATCH 107/160] Prevent corrupt values returned from the opencl code from trying to read beyond the end of the buffer by masking the value to a max of 15. --- findnonce.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/findnonce.c b/findnonce.c index 788835d9..344c7d15 100644 --- a/findnonce.c +++ b/findnonce.c @@ -252,6 +252,9 @@ static void *postcalc_hash(void *userdata) pthread_detach(pthread_self()); + /* To prevent corrupt values in FOUND from trying to read beyond the + * end of the res[] array */ + pcd->res[FOUND] &= FOUND; for (entry = 0; entry < pcd->res[FOUND]; entry++) { uint32_t nonce = pcd->res[entry]; From 461b7c6de29eed3bc97b45427e418ee499ae53cf Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 6 Oct 2012 15:12:05 +1000 Subject: [PATCH 108/160] Display correct pool number when block is found. --- cgminer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 6676c8ce..e9bfddca 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2633,7 +2633,7 @@ static void check_solve(struct work *work) work->pool->solved++; found_blocks++; work->mandatory = true; - applog(LOG_NOTICE, "Found block for pool %d!", work->pool); + applog(LOG_NOTICE, "Found block for pool %d!", work->pool->pool_no); } #endif } From 40b747bae6a775cb3cf8db935e62a1db0bf78b05 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Oct 2012 10:00:02 +1100 Subject: [PATCH 109/160] Put scrypt warning on separate line to avoid 0 being shown on windows as bufsize. --- miner.h | 2 +- ocl.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/miner.h b/miner.h index 169c9ee1..b2715d44 100644 --- a/miner.h +++ b/miner.h @@ -378,7 +378,7 @@ struct cgpu_info { #ifdef USE_SCRYPT int opt_lg, lookup_gap; - int opt_tc, thread_concurrency; + size_t opt_tc, thread_concurrency; int shaders; #endif struct timeval tv_gpustart; diff --git a/ocl.c b/ocl.c index 450a2d61..723ca30d 100644 --- a/ocl.c +++ b/ocl.c @@ -810,8 +810,8 @@ built: /* Use the max alloc value which has been rounded to a power of * 2 greater >= required amount earlier */ if (bufsize > cgpu->max_alloc) { - applog(LOG_WARNING, "Maximum buffer memory device %d supports says %u, your scrypt settings come to %u", - gpu, cgpu->max_alloc, bufsize); + applog(LOG_WARNING, "Maximum buffer memory device %d supports says %u", gpu, cgpu->max_alloc); + applog(LOG_WARNING, "Your scrypt settings come to %u", bufsize); } else bufsize = cgpu->max_alloc; applog(LOG_DEBUG, "Creating scrypt buffer sized %d", bufsize); From 58bba40a039449edfd6326ed47e2f1c608352004 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Oct 2012 10:19:52 +1100 Subject: [PATCH 110/160] fds need to be zeroed before set in modminer. --- driver-modminer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/driver-modminer.c b/driver-modminer.c index d15f2d88..cc8d162e 100644 --- a/driver-modminer.c +++ b/driver-modminer.c @@ -128,6 +128,7 @@ modminer_detect() } while(0) #define status_read(eng) do { \ +FD_ZERO(&fds); \ FD_SET(fd, &fds); \ select(fd+1, &fds, NULL, NULL, NULL); \ if (1 != read(fd, buf, 1)) \ @@ -139,7 +140,7 @@ select(fd+1, &fds, NULL, NULL, NULL); \ static bool modminer_fpga_upload_bitstream(struct cgpu_info*modminer) { -fd_set fds; + fd_set fds; char buf[0x100]; unsigned char *ubuf = (unsigned char*)buf; unsigned long len; From aa35fbcc9afbae8921b369fcc2376a93a6f47a78 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Oct 2012 10:21:20 +1100 Subject: [PATCH 111/160] Fix sign warning in ocl.c --- miner.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner.h b/miner.h index b2715d44..b53d2788 100644 --- a/miner.h +++ b/miner.h @@ -379,7 +379,7 @@ struct cgpu_info { #ifdef USE_SCRYPT int opt_lg, lookup_gap; size_t opt_tc, thread_concurrency; - int shaders; + size_t shaders; #endif struct timeval tv_gpustart; struct timeval tv_gpumid; From fefdb715343179f27ac88b0230705c69131a770e Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Oct 2012 10:26:42 +1100 Subject: [PATCH 112/160] Fix unused warnings on ming build. --- fpgautils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fpgautils.c b/fpgautils.c index de9d93e7..4c5829a1 100644 --- a/fpgautils.c +++ b/fpgautils.c @@ -74,7 +74,7 @@ int serial_autodetect_udev(__maybe_unused detectone_func_t detectone, __maybe_un } #endif -int serial_autodetect_devserial(detectone_func_t detectone, const char*prodname) +int serial_autodetect_devserial(__maybe_unused detectone_func_t detectone, __maybe_unused const char*prodname) { #ifndef WIN32 DIR *D; From 8dcdf81f8936f07867cef5422d1d47a6f8c041d4 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Oct 2012 10:38:42 +1100 Subject: [PATCH 113/160] Update NEWS. --- NEWS | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/NEWS b/NEWS index 115bf83c..24df5686 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,23 @@ +Version 2.7.7 - October 7, 2012 + +- Fix unused warnings on ming build. +- Fix sign warning in ocl.c +- fds need to be zeroed before set in modminer. +- Put scrypt warning on separate line to avoid 0 being shown on windows as +bufsize. +- Display correct pool number when block is found. +- Prevent corrupt values returned from the opencl code from trying to read +beyond the end of the buffer by masking the value to a max of 15. +- Icarus USB write failure is also a comms error +- api.c DEBUG message has no paramter +- Icarus catch more USB errors and close/reopen the port +- API-README update cgminer verison number +- hashmeter fix stats kh/s on 32bit windows + + Version 2.7.6 - September 24, 2012 +- Reorder libztex header include order to fix missing struct definition. - Display share difficulty on log with a shortened hash display on submission. - API stats add some pool getwork difficulty stats - Ignore any pings pushed to the worker threads if the thread is still paused to From cc3b693c6db5cabb76adcaf516b01ac45dda527e Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Oct 2012 12:25:19 +1100 Subject: [PATCH 114/160] Minor warning fixes. --- ocl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ocl.c b/ocl.c index 723ca30d..5b56e003 100644 --- a/ocl.c +++ b/ocl.c @@ -541,7 +541,7 @@ _clState *initCl(unsigned int gpu, char *name, size_t nameSize) strcat(binaryfilename, "g"); if (opt_scrypt) { #ifdef USE_SCRYPT - sprintf(numbuf, "lg%dtc%d", cgpu->lookup_gap, cgpu->thread_concurrency); + sprintf(numbuf, "lg%utc%u", cgpu->lookup_gap, (unsigned int)cgpu->thread_concurrency); strcat(binaryfilename, numbuf); #endif } else { @@ -614,7 +614,7 @@ build: #ifdef USE_SCRYPT if (opt_scrypt) sprintf(CompilerOptions, "-D LOOKUP_GAP=%d -D CONCURRENT_THREADS=%d -D WORKSIZE=%d", - cgpu->lookup_gap, cgpu->thread_concurrency, (int)clState->wsize); + cgpu->lookup_gap, (unsigned int)cgpu->thread_concurrency, (int)clState->wsize); else #endif { From 8faeeccfeb9301027da7e57b0a1eaad23680ed35 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Oct 2012 11:56:01 +1100 Subject: [PATCH 115/160] Bump version to 2.7.7 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index fe618e02..d0de0c83 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## m4_define([v_maj], [2]) m4_define([v_min], [7]) -m4_define([v_mic], [6]) +m4_define([v_mic], [7]) ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## m4_define([v_ver], [v_maj.v_min.v_mic]) m4_define([lt_rev], m4_eval(v_maj + v_min)) From 947a67ea243d02d7c53d60d546b8799eecd27621 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Oct 2012 12:52:48 +1100 Subject: [PATCH 116/160] Cope with broken drivers returning nonsense values for bitforce temperatures. --- driver-bitforce.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/driver-bitforce.c b/driver-bitforce.c index ded9e923..189daa61 100644 --- a/driver-bitforce.c +++ b/driver-bitforce.c @@ -410,6 +410,11 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce) if ((!strncasecmp(pdevbuf, "TEMP", 4)) && (s = strchr(pdevbuf + 4, ':'))) { float temp = strtof(s + 1, NULL); + /* Cope with older software that breaks and reads nonsense + * values */ + if (temp > 100) + temp = strtol(s + 1, NULL, 10); + if (temp > 0) { bitforce->temp = temp; if (unlikely(bitforce->cutofftemp > 0 && temp > bitforce->cutofftemp)) { From 735d77f349e4f71dd9e84c90fb0e55bb7812431d Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Oct 2012 12:59:02 +1100 Subject: [PATCH 117/160] Use strtod not strtol for bitforce temp backup. --- driver-bitforce.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-bitforce.c b/driver-bitforce.c index 189daa61..606ec2e6 100644 --- a/driver-bitforce.c +++ b/driver-bitforce.c @@ -413,7 +413,7 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce) /* Cope with older software that breaks and reads nonsense * values */ if (temp > 100) - temp = strtol(s + 1, NULL, 10); + temp = strtod(s + 1, NULL); if (temp > 0) { bitforce->temp = temp; From 1afb794cb3f90e52250a9f3393886c0a93a9e254 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Oct 2012 13:56:28 +1100 Subject: [PATCH 118/160] Cast socketfail to integer since SOCKET is an unsigned int on windows. --- util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util.h b/util.h index aec827d4..d5ac54c3 100644 --- a/util.h +++ b/util.h @@ -19,7 +19,7 @@ #include #define SOCKETTYPE SOCKET - #define SOCKETFAIL(a) ((a) == SOCKET_ERROR) + #define SOCKETFAIL(a) ((int)(a) == SOCKET_ERROR) #define INVSOCK INVALID_SOCKET #define INVINETADDR INADDR_NONE #define CLOSESOCKET closesocket From 2c80e16c85383bad61a450709eff92226c51aa98 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Oct 2012 13:58:34 +1100 Subject: [PATCH 119/160] Fix sign warning on windows build for bitforce. --- driver-bitforce.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-bitforce.c b/driver-bitforce.c index 606ec2e6..ae9fa01c 100644 --- a/driver-bitforce.c +++ b/driver-bitforce.c @@ -154,7 +154,7 @@ static int bitforce_autodetect_ftdi(void) char **bufptrs; char *buf; int found = 0; - int i; + DWORD i; FT_STATUS ftStatus; DWORD numDevs; From b41de69c354a95b04055ab530d99a4cb7ea82291 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Oct 2012 18:22:35 +1100 Subject: [PATCH 120/160] Fix various modminer warnings on mingw. --- driver-modminer.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/driver-modminer.c b/driver-modminer.c index cc8d162e..f052d43a 100644 --- a/driver-modminer.c +++ b/driver-modminer.c @@ -16,6 +16,7 @@ #include "logging.h" #include "miner.h" #include "fpgautils.h" +#include "util.h" #define BITSTREAM_FILENAME "fpgaminer_top_fixed7_197MHz.ncd" #define BISTREAM_USER_ID "\2\4$B" @@ -48,7 +49,7 @@ modminer_detect_one(const char *devpath) bailout(LOG_DEBUG, "ModMiner detect: failed to open %s", devpath); char buf[0x100]; - size_t len; + ssize_t len; // Sending 45 noops, just in case the device was left in "start job" reading (void)(write(fd, "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", 45) ?:0); @@ -186,7 +187,7 @@ modminer_fpga_upload_bitstream(struct cgpu_info*modminer) len = ((unsigned long)ubuf[0] << 24) | ((unsigned long)ubuf[1] << 16) | (ubuf[2] << 8) | ubuf[3]; applog(LOG_DEBUG, " Bitstream size: %lu", len); - int fd = modminer->device_fd; + SOCKETTYPE fd = modminer->device_fd; applog(LOG_WARNING, "%s %u: Programming %s... DO NOT EXIT CGMINER UNTIL COMPLETE", modminer->api->name, modminer->device_id, modminer->device_path); buf[0] = '\x05'; // Program Bitstream @@ -376,7 +377,7 @@ fd_set fds; struct cgpu_info*modminer = thr->cgpu; struct modminer_fpga_state *state = thr->cgpu_data; char fpgaid = thr->device_thread; - int fd = modminer->device_fd; + SOCKETTYPE fd = modminer->device_fd; char buf[1]; From 1614da682c40451fab59a8472f997d2adbb8c9ac Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Oct 2012 18:59:43 +1100 Subject: [PATCH 121/160] Update NEWS and README. --- NEWS | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ README | 16 ++++++ 2 files changed, 168 insertions(+) diff --git a/NEWS b/NEWS index 24df5686..32bfdd9c 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,155 @@ +Version 2.8.0 - October 7, 2012 + +- Major upgrade - support for the stratum mining protocol. +- Fix various modminer warnings on mingw. +- Fix sign warning on windows build for bitforce. +- Cast socketfail to integer since SOCKET is an unsigned int on windows. +- Use strtod not strtol for bitforce temp backup. +- Cope with broken drivers returning nonsense values for bitforce temperatures. +- Minor warning fixes. +- Use the stratum thread to detect when a stratum pool has died based on no +message for 2 minutes. +- Only set the stratum auth flag once and once the stratum thread is started, +use that to set/unset the stratum active flag. +- Only hand off to stratum from getwork if we succeed in initiating the +protocol. +- Target should only be 32 bytes copied. +- Use a static array for work submission data instead of stack memory. +- Clear the buffer data before sprinting to it. +- Clear work stratum strings before setting them and add them to debug output. +- Drop stratum connect failed message to verbose level only since it's a regular +probing message. +- TCP Keepalive in curl is only in very recent versions and not required with +regular messages on stratum anyway. +- Move stratum sockets to curl infrastructure with locking around send+recv to +begin support for proxies and ssl. +- Make detect stratum fail if a proxy has been set up. +- Stratum does not currently have any proxy support so do not try to switch to +stratum if a proxy has been specified. +- Windows doesn't work with MSG_PEEK on recv so move to a continuously updating +buffer for incoming messages. +- Alloca is unreliable on windows so use static arrays in util.c stratum code. +- Begin support for mingw stratum build. +- Add space to reject reason. +- Parse the reject reason where possible from stratum share submission. +- Pass json error value to share result function to be able to parse reject +reason in stratum. +- Don't try to parse unneeded parameters in response to mining.subscribe. +- Remove the sshare hash entry if we failed to send it. +- Change notify message to info level to avoid spamming repeatedly when a pool +is down. +- Check the stratum pool difference has not changed compared to the work diff +when testing whether a share meets the target or not and retarget if necessary. +- Bit error in target calculation for stratum. +- Set work_block in gen_stratum_work for when work is reused to avoid thinking +it's all stale. +- Offset the current block detection to the prev block hash. +- We should be testing for id_val, not id in parse stratum response. +- Make target on stratum scale to any size by clearing sequential bits according +to diff. +- Correct target calculation in gen_stratum_work. +- If a share result has an error code but still has an id, it is likely a +reject, not an error. +- Initiate stratum the first time in pool_active only, allowing us to switch to +it on getting a failed getwork and detecting the presence of stratum on the url +at that time. +- Use 5 second timeout on sock full for now as a temporary workaround. +- If no stratum url is set by the end of the detect stratum routine, copy the +sockaddr url. +- Make all buffers slightly larger to prevent overflow. +- Make the stratum recv buffer larger than the recvsize. +- Userpass needs to be copied to user and pass earlier to allow stratum +authorisation to work with it. +- Store a sockaddr url of the stripped url used in determining sockaddr to not +confuse it with the stratum url and fix build warnings. +- Decrease the queued count with stratum work once it's staged as well. +- Allow the stratum retry to initiate and auth stratum in pool_alive to make +sure the stratum thread is started. +- Avoid duplicating pool->rpc_url and setting pool->stratum_url twice to itself. +- Detect if a getwork based pool has the X-Stratum header on startup, and if so, +switch to the stratum based pool. +- Comment update. +- Minor message change. +- Create a work item from a "clean" request from stratum allowing the new block +to be detected and the appropriate block change message to be given. +- Use statically allocated stratum strings in struct work to cope with the +inability to safely deallocate dynamically allocated ram. +- Use the current pool when deciding whether to reuse work from a stratum source +rather than the work's previous pool. +- Copy the stratum url to the rpc url to avoid none being set. +- Provide locking around stratum send operations to avoid races. +- Submit shares from stratum through the abstracted submit share function +detecting what message they belong to and showing the data from the associated +work, and then deleting it from the hash. +- Use a more robust mechanism to obtain a \n terminated string over a socket. +- Abstract out share submit as a function to be useable by stratum. +- Rename parse_stratum to parse_method as it is only for stratum messages that +contain methods. +- Display stratum as mechanism in status line when current pool is running it. +- Count each stratum notify as a getwork equivalent. +- Correct nonce submitted with share. +- Extranonce2 should be added before coinbase2. +- We should be hashing the binary coinbase, not the hex one. +- Fix endianness of nonce submitted for stratum. +- Check that stratum is already active in initiate_stratum to avoid +de-authorising ourselves by subscribing again. +- Begin implementing a hash database of submissions and attempt sending results. +- Copy parameters from stratum work required for share submission. +- Set lagging flag on first adding a pool to prevent pool slow warning at +startup. +- Fix work->target being a 32 byte binary in gen_stratum_work. +- Store and display stripped url in its own variable. +- Create machinery to divert work requests to stratum. +- Generate the work target in gen_stratum_work, setting default diff to 1 in +case it is not yet set. +- Generate work data, midstate and hash1 in gen_stratum_work. +- Generate header created from stratum structures in gen_stratum_work. +- Generate merkle root hash in gen_stratum_work. +- Generate the coinbase for generation of stratum based work. +- The number of transactions is variable so make merkle a variable length +dynamically allocated array and track how many there are for stratum. +- Rename nonce2 to n2size reflecting that it's a size variable and not the +actual nonce. +- Provide rudimentary support for stratum clean work command in the stratum +thread. +- Cope with pools being removed in the stratum thread. +- Use the pool sock value directly in the stratum thread in case it changes +after reconnecting. +- Create a stratum thread per pool that has stratum that monitors the socket and +serves received data. +- Check return value of stratum_parse. +- Complete authorisation in stratum. +- Implement stratum parsing of notify parameters and storing them in the pool +stratum work structure. +- Create helper functions for duplicating json strings to avoid keeping json +references in use. +- Append \n in the sock_send function instead of adding it when constructing +json in stratum. +- Don't keep any json references around with stratum structures. +- Create parse_stratum function that hands off stratum parameters to other +functions to manage pool stratum work struct variables. Implement mining +difficulty setting. +- Create helper functions for checking when a socket is ready to read on and +receive a single line at a time. Begin stratum authorisation process. +- Provide a helper function for reading a single \n terminated string from a +socket. +- Create a stratum work structure to store current work variables. +- Test specifically for stratum being active in pool_active. +- Detect stratum in common place when adding urls, and use a bool to tell us +when it's active. +- Fix warnings. +- Extract and store various parameters on stratum init confirming successful +mining notify. +- Use existing socket macros and close the socket on failure in init stratum. +- Initiate stratum and grab first json result. +- Get detailed addressinfo from the parsed URL for future raw socket usage when +possible. IPV4 only for now. +- Prepare for getaddrinfo call. +- Add data structures to pool struct for socket communications. +- Put all socket definitions in util.h to allow reusing by added socket +functions to be used in util.c. + + Version 2.7.7 - October 7, 2012 - Fix unused warnings on ming build. diff --git a/README b/README index c034a7c5..18ecc71b 100644 --- a/README +++ b/README @@ -304,6 +304,10 @@ Single pool with a socks5 proxy, regular desktop: cgminer -o "socks5:proxy:port|http://pool:port" -u username -p password +Single pool with stratum protocol support: + +cgminer -o stratum+tcp://pool:port -u username -p password + The list of proxy types are: http: standard http 1.1 proxy http0: http 1.0 proxy @@ -908,6 +912,18 @@ To permanently give your account the 'dialout' group: sudo usermod -G dialout -a `whoami` Then logout and back in again +Q: What is stratum and how do I use it? +A: Stratum is a protocol designed for pooled mining in such a way as to +minimise the amount of network communications, yet scale to hardware of any +speed. With versions of cgminer 2.8.0+, if a pool has stratum support, cgminer +will automatically detect it and switch to the support as advertised if it can. +Stratum uses direct TCP connections to the pool and thus it will NOT currently +work through a http proxy but will work via a socks proxy if you need to use +one. If you input the stratum port directly into your configuration, or use the +special prefix "stratum+tcp://" instead of "http://", cgminer will ONLY try to +use stratum protocol mining. The advantages of stratum to the miner are no +delays in getting more work for the miner, less rejects across block changes, +and far less network communications for the same amount of mining hashrate. --- From f25c34bfaa250e55a42d2879b86d038bdd39524b Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 7 Oct 2012 19:00:10 +1100 Subject: [PATCH 122/160] Bump version to 2.8.0 --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index aa0ea0bf..3e038883 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## m4_define([v_maj], [2]) -m4_define([v_min], [7]) -m4_define([v_mic], [7]) +m4_define([v_min], [8]) +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 ef822a25ed44e447815b0b10020fd08ea2cef504 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Oct 2012 11:08:04 +1100 Subject: [PATCH 123/160] Detect stratum outage based on either select timing out or receiving an empty buffer and properly re-establish connection by disabling the stratum_active flag, coping with empty buffers in parse_stratum. --- cgminer.c | 14 +++++++++----- util.c | 5 ++++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/cgminer.c b/cgminer.c index c08cfe14..37eeda18 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4163,24 +4163,28 @@ static void *stratum_thread(void *userdata) * every minute so if we fail to receive any for 2 minutes we * assume the connection has been dropped and treat this pool * as dead */ - if (select(pool->sock + 1, &rd, NULL, NULL, &timeout) < 1) { + select(pool->sock + 1, &rd, NULL, NULL, &timeout); + s = recv_line(pool); + if (!s) { applog(LOG_INFO, "Stratum connection to pool %d interrupted", pool->pool_no); pool->getfail_occasions++; total_go++; + pool->stratum_active = false; + if (initiate_stratum(pool) && auth_stratum(pool)) + continue; + pool_died(pool); while (!initiate_stratum(pool) || !auth_stratum(pool)) { if (pool->removed) goto out; - sleep(5); + sleep(30); } applog(LOG_INFO, "Stratum connection to pool %d resumed", pool->pool_no); pool_resus(pool); continue; } - s = recv_line(pool); - if (unlikely(!s)) - continue; + if (!parse_method(pool, s) && !parse_stratum_response(s)) applog(LOG_INFO, "Unknown stratum msg: %s", s); free(s); diff --git a/util.c b/util.c index d39d1038..6d6409bc 100644 --- a/util.c +++ b/util.c @@ -1103,6 +1103,9 @@ bool parse_method(struct pool *pool, char *s) bool ret = false; char *buf; + if (!s) + goto out; + val = JSON_LOADS(s, &err); if (!val) { applog(LOG_INFO, "JSON decode failed(%d): %s", err.line, err.text); @@ -1166,7 +1169,7 @@ bool auth_stratum(struct pool *pool) sret = recv_line(pool); if (!parse_method(pool, sret)) { clear_sock(pool); - applog(LOG_WARNING, "Failed to parse stratum buffer"); + applog(LOG_INFO, "Failed to parse stratum buffer"); free(sret); return ret; } From 2023e53fb2ff6ed0f900f6fc3e2bd4d5ed07798c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Oct 2012 13:48:18 +1100 Subject: [PATCH 124/160] Cope with one stratum pool being the only active pool when it dies by sleeping for 5 seconds before retrying to get work from it instead of getting work indefinitely. --- cgminer.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 37eeda18..b3d8f194 100644 --- a/cgminer.c +++ b/cgminer.c @@ -2581,17 +2581,27 @@ static void gen_stratum_work(struct pool *pool, struct work *work); static void *get_work_thread(void *userdata) { struct workio_cmd *wc = (struct workio_cmd *)userdata; - struct pool *pool = current_pool(); struct work *ret_work= NULL; struct curl_ent *ce = NULL; + struct pool *pool; pthread_detach(pthread_self()); applog(LOG_DEBUG, "Creating extra get work thread"); +retry: pool = wc->pool; if (pool->has_stratum) { + while (!pool->stratum_active) { + struct pool *altpool = select_pool(true); + + if (altpool != pool) { + wc->pool = altpool; + goto retry; + } + sleep(5); + } ret_work = make_work(); gen_stratum_work(pool, ret_work); if (unlikely(!stage_work(ret_work))) { @@ -4457,6 +4467,8 @@ static struct work *hash_pop(const struct timespec *abstime) static bool reuse_work(struct work *work, struct pool *pool) { if (pool->has_stratum) { + if (!pool->stratum_active) + return false; applog(LOG_DEBUG, "Reusing stratum work"); gen_stratum_work(pool, work);; return true; @@ -4662,6 +4674,13 @@ retry: if (reuse_work(work, pool)) goto out; + /* If we were unable to reuse work from a stratum pool, it implies the + * pool is inactive and unless we have another pool to grab work from + * we can only wait till it comes alive or another pool comes online */ + if (pool->has_stratum) { + sleep(5); + goto retry; + } if (!pool->lagging && !total_staged() && global_queued() >= mining_threads + opt_queue) { struct cgpu_info *cgpu = thr->cgpu; bool stalled = true; From 662ab1eff738d341d39414c53aecf35a98eacc55 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Oct 2012 21:34:46 +1100 Subject: [PATCH 125/160] Count each stratum work item as local work. --- cgminer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cgminer.c b/cgminer.c index b3d8f194..4add1cd3 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4640,6 +4640,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work) set_work_target(work, work->sdiff); + local_work++; work->pool = pool; work->stratum = true; work->blk.nonce = 0; From 2b6e3676cd6e056615aaf3207fdcbf42117f9b98 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Oct 2012 22:10:15 +1100 Subject: [PATCH 126/160] Count an invalid nonce count as a hardware error on opencl. --- findnonce.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/findnonce.c b/findnonce.c index 344c7d15..2bfc1ef8 100644 --- a/findnonce.c +++ b/findnonce.c @@ -254,7 +254,14 @@ static void *postcalc_hash(void *userdata) /* To prevent corrupt values in FOUND from trying to read beyond the * end of the res[] array */ - pcd->res[FOUND] &= FOUND; + if (unlikely(pcd->res[FOUND] & ~FOUND)) { + applog(LOG_WARNING, "%s%d: invalid nonce count - HW error", + thr->cgpu->api->name, thr->cgpu->device_id); + hw_errors++; + thr->cgpu->hw_errors++; + pcd->res[FOUND] &= FOUND; + } + for (entry = 0; entry < pcd->res[FOUND]; entry++) { uint32_t nonce = pcd->res[entry]; From 7d6bcab899192806b106b5fb73d4ea736aa34431 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Oct 2012 22:15:30 +1100 Subject: [PATCH 127/160] Use the stratum url as the rpc url advertised if we switch to it. --- cgminer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cgminer.c b/cgminer.c index 4add1cd3..c410c722 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4285,6 +4285,8 @@ retry_stratum: * and if so, switch to that in preference to getwork if it works */ if (pool->stratum_url && stratum_works(pool)) { applog(LOG_NOTICE, "Switching pool %d %s to %s", pool->pool_no, pool->rpc_url, pool->stratum_url); + free(pool->rpc_url); + pool->rpc_url = strdup(pool->stratum_url); pool->has_stratum = true; curl_easy_cleanup(curl); From 295469ca77a5a3201ebda25ac77442bb51eacde8 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Oct 2012 22:47:08 +1100 Subject: [PATCH 128/160] Update news. --- NEWS | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/NEWS b/NEWS index 32bfdd9c..b7115f84 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,16 @@ +Version 2.8.1 - October 8, 2012 + +- Use the stratum url as the rpc url advertised if we switch to it. +- Count an invalid nonce count as a hardware error on opencl. +- Count each stratum work item as local work. +- Cope with one stratum pool being the only active pool when it dies by sleeping +for 5 seconds before retrying to get work from it instead of getting work +indefinitely. +- Detect stratum outage based on either select timing out or receiving an empty +buffer and properly re-establish connection by disabling the stratum_active +flag, coping with empty buffers in parse_stratum. + + Version 2.8.0 - October 7, 2012 - Major upgrade - support for the stratum mining protocol. From e0864a61d1c6c67d3905b1f68e17ef0a64d3964f Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Oct 2012 22:48:06 +1100 Subject: [PATCH 129/160] Bump version to 2.8.1 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 3e038883..bb116ec6 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## m4_define([v_maj], [2]) m4_define([v_min], [8]) -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 80d4355737e9f8e5adedd253ae4d470a68bd70a0 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 8 Oct 2012 22:59:50 +1100 Subject: [PATCH 130/160] Remove free that could segfault. --- cgminer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index c410c722..6a2f3af1 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4285,7 +4285,6 @@ retry_stratum: * and if so, switch to that in preference to getwork if it works */ if (pool->stratum_url && stratum_works(pool)) { applog(LOG_NOTICE, "Switching pool %d %s to %s", pool->pool_no, pool->rpc_url, pool->stratum_url); - free(pool->rpc_url); pool->rpc_url = strdup(pool->stratum_url); pool->has_stratum = true; curl_easy_cleanup(curl); From 07605fad600a84f94637cf795fab81b60f54793f Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 10 Oct 2012 23:07:33 +1100 Subject: [PATCH 131/160] stratum auth can be unset if we fail to authorise on subsequent calls to auth_stratum which undoes the requirement of setting it in one place so set it in pool_active. --- cgminer.c | 1 + util.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index 6a2f3af1..71bae1d0 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4265,6 +4265,7 @@ retry_stratum: return false; if (!auth_stratum(pool)) return false; + pool->stratum_auth = true; pool->idle = false; init_stratum_thread(pool); return true; diff --git a/util.c b/util.c index 6d6409bc..3b90f8e8 100644 --- a/util.c +++ b/util.c @@ -1205,8 +1205,6 @@ out: if (val) json_decref(val); - pool->stratum_auth = ret; - return ret; } From 974f65c67f2ca3f512eec69b7a1620e4979302ee Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 10 Oct 2012 23:22:24 +1100 Subject: [PATCH 132/160] Ignore the value of stratum_active on calling initiate_stratum and assume we're always trying to reinitiate it, and set the active flag to false in that function. --- cgminer.c | 1 - util.c | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/cgminer.c b/cgminer.c index 71bae1d0..27de6cbc 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4180,7 +4180,6 @@ static void *stratum_thread(void *userdata) pool->getfail_occasions++; total_go++; - pool->stratum_active = false; if (initiate_stratum(pool) && auth_stratum(pool)) continue; diff --git a/util.c b/util.c index 3b90f8e8..42644406 100644 --- a/util.c +++ b/util.c @@ -1217,9 +1217,6 @@ bool initiate_stratum(struct pool *pool) json_error_t err; bool ret = false; - if (pool->stratum_active) - return true; - if (!pool->stratum_curl) { pool->stratum_curl = curl_easy_init(); if (unlikely(!pool->stratum_curl)) @@ -1319,6 +1316,7 @@ out: pool->pool_no, pool->nonce1, pool->n2size); } } else { + pool->stratum_active = false; if (curl) { curl_easy_cleanup(curl); pool->stratum_curl = NULL; From 783af8768b595613ee5e4aabfefde24c0830e71a Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 10 Oct 2012 23:41:29 +1100 Subject: [PATCH 133/160] Implement rudimentary mining.reconnect support for stratum. --- util.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/util.c b/util.c index 42644406..d5243ae7 100644 --- a/util.c +++ b/util.c @@ -850,6 +850,7 @@ bool extract_sockaddr(struct pool *pool, char *url) pool->server = (struct sockaddr_in *)res->ai_addr; pool->sockaddr_url = strdup(url_address); + return true; } @@ -1096,6 +1097,27 @@ static bool parse_diff(struct pool *pool, json_t *val) return true; } +static bool parse_reconnect(struct pool *pool, json_t *val) +{ + char *url; + + url = (char *)json_string_value(json_array_get(val, 0)); + if (!url) + return false; + + if (!extract_sockaddr(pool, url)) + return false; + + pool->stratum_url = pool->sockaddr_url; + + applog(LOG_NOTICE, "Reconnect requested from pool %d to %s", pool->pool_no, pool->stratum_url); + + if (!initiate_stratum(pool) || !auth_stratum(pool)) + return false; + + return true; +} + bool parse_method(struct pool *pool, char *s) { json_t *val = NULL, *method, *err_val, *params; @@ -1147,6 +1169,11 @@ bool parse_method(struct pool *pool, char *s) goto out; } + if (!strncasecmp(buf, "mining.reconnect", 16) && parse_reconnect(pool, params)) { + ret = true; + goto out; + } + out: if (val) json_decref(val); From ef6ad423e3ab9f07354039d271c40a9317ca0fcf Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 10 Oct 2012 23:46:49 +1100 Subject: [PATCH 134/160] Only copy the stratum url to the rpc url if an rpc url does not exist. --- cgminer.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index 27de6cbc..05729e06 100644 --- a/cgminer.c +++ b/cgminer.c @@ -588,7 +588,8 @@ static char *set_url(char *arg) arg = get_proxy(arg, pool); if (detect_stratum(pool, arg)) { - pool->rpc_url = strdup(pool->stratum_url); + if (!pool->rpc_url) + pool->rpc_url = strdup(pool->stratum_url); return NULL; } @@ -4285,7 +4286,8 @@ retry_stratum: * and if so, switch to that in preference to getwork if it works */ if (pool->stratum_url && stratum_works(pool)) { applog(LOG_NOTICE, "Switching pool %d %s to %s", pool->pool_no, pool->rpc_url, pool->stratum_url); - pool->rpc_url = strdup(pool->stratum_url); + if (!pool->rpc_url) + pool->rpc_url = strdup(pool->stratum_url); pool->has_stratum = true; curl_easy_cleanup(curl); From 7c04a00e629ad52b55cbff5c40f9d26f6118eb6e Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 10 Oct 2012 23:56:24 +1100 Subject: [PATCH 135/160] The command for stratum is client.reconnect, not mining.reconnect. --- util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util.c b/util.c index d5243ae7..a9ac600c 100644 --- a/util.c +++ b/util.c @@ -1169,7 +1169,7 @@ bool parse_method(struct pool *pool, char *s) goto out; } - if (!strncasecmp(buf, "mining.reconnect", 16) && parse_reconnect(pool, params)) { + if (!strncasecmp(buf, "client.reconnect", 16) && parse_reconnect(pool, params)) { ret = true; goto out; } From 5226a399c784f960ceccde1dcf838f8f4f100a50 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 11 Oct 2012 00:06:44 +1100 Subject: [PATCH 136/160] Look for null values and parse correct separate array entries for url and port with client reconnect commands for stratum. --- util.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/util.c b/util.c index a9ac600c..e12a9f78 100644 --- a/util.c +++ b/util.c @@ -1099,13 +1099,20 @@ static bool parse_diff(struct pool *pool, json_t *val) static bool parse_reconnect(struct pool *pool, json_t *val) { - char *url; + char *url, *port, address[256]; + memset(address, 0, 255); url = (char *)json_string_value(json_array_get(val, 0)); if (!url) - return false; + url = pool->sockaddr_url; + + port = (char *)json_string_value(json_array_get(val, 1)); + if (!port) + port = pool->stratum_port; + + sprintf(address, "%s:%s", url, port); - if (!extract_sockaddr(pool, url)) + if (!extract_sockaddr(pool, address)) return false; pool->stratum_url = pool->sockaddr_url; From a533f106fd31f74edc7aa60a56ee94150a2a01b0 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 11 Oct 2012 00:08:45 +1100 Subject: [PATCH 137/160] Update reconnect message to show whole address including port. --- util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util.c b/util.c index e12a9f78..316410de 100644 --- a/util.c +++ b/util.c @@ -1117,7 +1117,7 @@ static bool parse_reconnect(struct pool *pool, json_t *val) pool->stratum_url = pool->sockaddr_url; - applog(LOG_NOTICE, "Reconnect requested from pool %d to %s", pool->pool_no, pool->stratum_url); + applog(LOG_NOTICE, "Reconnect requested from pool %d to %s", pool->pool_no, address); if (!initiate_stratum(pool) || !auth_stratum(pool)) return false; From ca962ee58bad8373a76cf6c303abd0e5625bb710 Mon Sep 17 00:00:00 2001 From: ckolivas Date: Thu, 11 Oct 2012 10:46:45 +1100 Subject: [PATCH 138/160] Use a 64 bit unsigned integer on the diff target to generate the hex target. --- cgminer.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/cgminer.c b/cgminer.c index 05729e06..8bc0e24e 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4533,18 +4533,13 @@ static void gen_hash(unsigned char *data, unsigned char *hash, int len) static void set_work_target(struct work *work, int diff) { unsigned char rtarget[33], target[33]; - uint8_t *data8; - int i, j; - - /* Scale to any diff by setting number of bits according to diff */ - hex2bin(rtarget, "00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 32); - data8 = (uint8_t *)(rtarget + 4); - for (i = 1, j = 0; i < diff; i++, j++) { - int byte = j / 8; - int bit = j % 8; + uint64_t *data64, h64; - data8[byte] &= ~(128 >> bit); - } + hex2bin(rtarget, "00000000ffff0000000000000000000000000000000000000000000000000000", 32); + data64 = (uint64_t *)(rtarget + 4); + h64 = be64toh(*data64); + h64 /= (uint64_t)diff; + *data64 = htobe64(h64); swab256(target, rtarget); if (opt_debug) { char *htarget = bin2hex(target, 32); From 7f522ef83c335f26fa11bd9ba230822dd3aa8b93 Mon Sep 17 00:00:00 2001 From: ckolivas Date: Thu, 11 Oct 2012 14:23:09 +1100 Subject: [PATCH 139/160] Add support for client.get_version for stratum. --- util.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/util.c b/util.c index 316410de..91a67182 100644 --- a/util.c +++ b/util.c @@ -1125,6 +1125,21 @@ static bool parse_reconnect(struct pool *pool, json_t *val) return true; } +static bool send_version(struct pool *pool, json_t *val) +{ + char s[RBUFSIZE]; + int id = json_integer_value(json_object_get(val, "id")); + + if (!id) + return false; + + sprintf(s, "{\"id\": %d, \"result\": \""PACKAGE"/"VERSION"\", \"error\": null}", id); + if (!stratum_send(pool, s, strlen(s))) + return false; + + return true; +} + bool parse_method(struct pool *pool, char *s) { json_t *val = NULL, *method, *err_val, *params; @@ -1181,6 +1196,10 @@ bool parse_method(struct pool *pool, char *s) goto out; } + if (!strncasecmp(buf, "client.get_version", 18) && send_version(pool, val)) { + ret = true; + goto out; + } out: if (val) json_decref(val); From 5ed6e9d55ea774fdfc6d9516c25f9d04fc580c09 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 11 Oct 2012 19:31:24 +1100 Subject: [PATCH 140/160] Simplify target generation code. --- cgminer.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/cgminer.c b/cgminer.c index 8bc0e24e..0be058cb 100644 --- a/cgminer.c +++ b/cgminer.c @@ -4530,15 +4530,19 @@ static void gen_hash(unsigned char *data, unsigned char *hash, int len) sha2(hash1, 32, hash, false); } +/* Diff 1 is a 256 bit unsigned integer of + * 0x00000000ffff0000000000000000000000000000000000000000000000000000 + * so we use a big endian 64 bit unsigned integer centred on the 5th byte to + * cover a huge range of difficulty targets, though not all 256 bits' worth */ static void set_work_target(struct work *work, int diff) { unsigned char rtarget[33], target[33]; uint64_t *data64, h64; - hex2bin(rtarget, "00000000ffff0000000000000000000000000000000000000000000000000000", 32); - data64 = (uint64_t *)(rtarget + 4); - h64 = be64toh(*data64); + h64 = 0xFFFF000000000000ull; h64 /= (uint64_t)diff; + memset(rtarget, 0, 32); + data64 = (uint64_t *)(rtarget + 4); *data64 = htobe64(h64); swab256(target, rtarget); if (opt_debug) { From d211f8e0b050ea24711f58d0948fe82c92db65fa Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 11 Oct 2012 19:52:40 +1100 Subject: [PATCH 141/160] Create a fix-protocol option which prevents cgminer from switching to stratum if it's detected. --- README | 5 ++++- cgminer.c | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/README b/README index 18ecc71b..0d17e8af 100644 --- a/README +++ b/README @@ -146,6 +146,7 @@ Options for both config file and command line: --debug|-D Enable debug output --expiry|-E Upper bound on how many seconds after getting work we consider a share from it stale (default: 120) --failover-only Don't leak work to backup pools when primary pool is lagging +--fix-protocol Do not redirect to a different getwork protocol (eg. stratum) --kernel-path|-K Specify a path to where bitstream and kernel files are (default: "/usr/local/bin") --load-balance Change multipool strategy from failover to efficiency based balance --log|-l Interval in seconds between log output (default: 5) @@ -923,7 +924,9 @@ one. If you input the stratum port directly into your configuration, or use the special prefix "stratum+tcp://" instead of "http://", cgminer will ONLY try to use stratum protocol mining. The advantages of stratum to the miner are no delays in getting more work for the miner, less rejects across block changes, -and far less network communications for the same amount of mining hashrate. +and far less network communications for the same amount of mining hashrate. If +you do NOT wish cgminer to automatically switch to stratum protocol even if it +is detected, add the --fix-protocol option. --- diff --git a/cgminer.c b/cgminer.c index 0be058cb..d31a022c 100644 --- a/cgminer.c +++ b/cgminer.c @@ -129,6 +129,7 @@ bool use_curses; static bool opt_submit_stale = true; static int opt_shares; bool opt_fail_only; +static bool opt_fix_protocol; bool opt_autofan; bool opt_autoengine; bool opt_noadl; @@ -893,6 +894,9 @@ static struct opt_table opt_config_table[] = { OPT_WITHOUT_ARG("--failover-only", opt_set_bool, &opt_fail_only, "Don't leak work to backup pools when primary pool is lagging"), + OPT_WITHOUT_ARG("--fix-protocol", + opt_set_bool, &opt_fix_protocol, + "Do not redirect to a different getwork protocol (eg. stratum)"), #ifdef HAVE_OPENCL OPT_WITH_ARG("--gpu-dyninterval", set_int_1_to_65535, opt_show_intval, &opt_dynamic_interval, @@ -4284,7 +4288,7 @@ retry_stratum: /* Detect if a http getwork pool has an X-Stratum header at startup, * and if so, switch to that in preference to getwork if it works */ - if (pool->stratum_url && stratum_works(pool)) { + if (pool->stratum_url && !opt_fix_protocol && stratum_works(pool)) { applog(LOG_NOTICE, "Switching pool %d %s to %s", pool->pool_no, pool->rpc_url, pool->stratum_url); if (!pool->rpc_url) pool->rpc_url = strdup(pool->stratum_url); From 4fbc570fa41029655fa8322cdfb66fbad75f2b11 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 11 Oct 2012 20:30:47 +1100 Subject: [PATCH 142/160] Reinstate the history on dynamic intensity mode to damp fluctuations in intensity but use an upper limit on how much the value can increase at any time to cope with rare overflows. --- driver-opencl.c | 9 +++++++-- miner.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/driver-opencl.c b/driver-opencl.c index 82cbc6bb..063c5c10 100644 --- a/driver-opencl.c +++ b/driver-opencl.c @@ -1585,14 +1585,19 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work, gpu_us = us_tdiff(&tv_gpuend, &gpu->tv_gpumid); if (gpu_us > 0 && ++gpu->hit > 4) { gpu_us = us_tdiff(&tv_gpuend, &gpu->tv_gpustart) / gpu->intervals; + /* Very rarely we may get an overflow so put an upper + * limit on the detected time */ + if (gpu_us > gpu->gpu_us_average * 4) + gpu_us = gpu->gpu_us_average * 4; + gpu->gpu_us_average = (gpu->gpu_us_average + gpu_us * 0.63) / 1.63; /* Try to not let the GPU be out for longer than * opt_dynamic_interval in ms, but increase * intensity when the system is idle in dynamic mode */ - if (gpu_us > dynamic_us) { + if (gpu->gpu_us_average > dynamic_us) { if (gpu->intensity > MIN_INTENSITY) --gpu->intensity; - } else if (gpu_us < dynamic_us / 2) { + } else if (gpu->gpu_us_average < dynamic_us / 2) { if (gpu->intensity < MAX_INTENSITY) ++gpu->intensity; } diff --git a/miner.h b/miner.h index 19e1e535..479be8d9 100644 --- a/miner.h +++ b/miner.h @@ -397,6 +397,7 @@ struct cgpu_info { #endif struct timeval tv_gpustart; struct timeval tv_gpumid; + double gpu_us_average; int intervals, hit; #endif From 78f2be1624b154a19e1446be1cb5a0139beb5d1a Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 11 Oct 2012 20:33:26 +1100 Subject: [PATCH 143/160] Update NEWS. --- NEWS | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/NEWS b/NEWS index b7115f84..4b154853 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,27 @@ +Version 2.8.2 - October 11, 2012 + +- Reinstate the history on dynamic intensity mode to damp fluctuations in +intensity but use an upper limit on how much the value can increase at any time +to cope with rare overflows. +- Create a fix-protocol option which prevents cgminer from switching to stratum +if it's detected. +- Simplify target generation code. +- Add support for client.get_version for stratum. +- Use a 64 bit unsigned integer on the diff target to generate the hex target. +- Update reconnect message to show whole address including port. +- Look for null values and parse correct separate array entries for url and port +with client reconnect commands for stratum. +- The command for stratum is client.reconnect, not mining.reconnect. +- Only copy the stratum url to the rpc url if an rpc url does not exist. +- Implement rudimentary mining.reconnect support for stratum. +- Ignore the value of stratum_active on calling initiate_stratum and assume +we're always trying to reinitiate it, and set the active flag to false in that +function. +- stratum auth can be unset if we fail to authorise on subsequent calls to +auth_stratum which undoes the requirement of setting it in one place so set it +in pool_active. + + Version 2.8.1 - October 8, 2012 - Use the stratum url as the rpc url advertised if we switch to it. From ccaf73148187d035dda824eb988633c9a50c8e66 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 11 Oct 2012 20:33:45 +1100 Subject: [PATCH 144/160] Bump version to 2.8.2 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index bb116ec6..03583f3a 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## m4_define([v_maj], [2]) m4_define([v_min], [8]) -m4_define([v_mic], [1]) +m4_define([v_mic], [2]) ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## m4_define([v_ver], [v_maj.v_min.v_mic]) m4_define([lt_rev], m4_eval(v_maj + v_min)) From a977fa476643a9631e825b1c6095d5726e3ede10 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 11 Oct 2012 20:46:04 +1100 Subject: [PATCH 145/160] Fix lack of htobe64 on mingw32. --- miner.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/miner.h b/miner.h index 479be8d9..a74740f6 100644 --- a/miner.h +++ b/miner.h @@ -139,14 +139,17 @@ static inline int fsync (int fd) #endif #endif /* !defined(__GLXBYTEORDER_H__) */ -/* This assumes htobe32 is a macro in endian.h */ +/* This assumes htobe32 is a macro in endian.h, and if it doesn't exist, then + * htobe64 also won't exist */ #ifndef htobe32 # if __BYTE_ORDER == __LITTLE_ENDIAN # define be32toh(x) bswap_32(x) # define htobe32(x) bswap_32(x) +# define htobe64(x) bswap_32(x) # elif __BYTE_ORDER == __BIG_ENDIAN # define be32toh(x) (x) # define htobe32(x) (x) +# define htobe64(x) (x) #else #error UNKNOWN BYTE ORDER #endif From d15c70f8a8c5b4fc14a63284710bd4f5859c1e23 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 12 Oct 2012 11:30:35 +1100 Subject: [PATCH 146/160] Fix wrong byteswap macro being used on mingw32 which was breaking target generation on stratum. --- miner.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner.h b/miner.h index a74740f6..3a65d755 100644 --- a/miner.h +++ b/miner.h @@ -145,7 +145,7 @@ static inline int fsync (int fd) # if __BYTE_ORDER == __LITTLE_ENDIAN # define be32toh(x) bswap_32(x) # define htobe32(x) bswap_32(x) -# define htobe64(x) bswap_32(x) +# define htobe64(x) bswap_64(x) # elif __BYTE_ORDER == __BIG_ENDIAN # define be32toh(x) (x) # define htobe32(x) (x) From 55396f534ed16f59b4d9663091ff40185d5f3302 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 12 Oct 2012 11:35:20 +1100 Subject: [PATCH 147/160] Fix 4 * 0 being 0 that would break dynamic intensity mode. --- driver-opencl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-opencl.c b/driver-opencl.c index 063c5c10..d558a820 100644 --- a/driver-opencl.c +++ b/driver-opencl.c @@ -1587,7 +1587,7 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work, gpu_us = us_tdiff(&tv_gpuend, &gpu->tv_gpustart) / gpu->intervals; /* Very rarely we may get an overflow so put an upper * limit on the detected time */ - if (gpu_us > gpu->gpu_us_average * 4) + if (unlikely(gpu->gpu_us_average > 0 && gpu_us > gpu->gpu_us_average * 4)) gpu_us = gpu->gpu_us_average * 4; gpu->gpu_us_average = (gpu->gpu_us_average + gpu_us * 0.63) / 1.63; From 420fdf32d6262a5b7998a44df0822c9e72f5f027 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 12 Oct 2012 14:17:29 +1100 Subject: [PATCH 148/160] Display the actual share diff next to the pool required diff, using a suffix creation function to prevent values of >1000 being shown in their entirety. --- cgminer.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- miner.h | 2 ++ 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index d31a022c..cd2c31ba 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1472,6 +1472,51 @@ void tailsprintf(char *f, const char *fmt, ...) va_end(ap); } +/* Convert a uint64_t value into a truncated string for displaying with its + * associated suitable for Mega, Giga etc. Buf array needs to be long enough */ +static void suffix_string(uint64_t val, char *buf, int sigdigits) +{ + const uint64_t kilo = 1000ull; + const uint64_t mega = 1000000ull; + const uint64_t giga = 1000000000ull; + const uint64_t tera = 1000000000000ull; + const uint64_t peta = 1000000000000000ull; + const uint64_t exa = 1000000000000000000ull; + char suffix[2] = ""; + double dval; + + if (val >= exa) { + val /= peta; + dval = (double)val / kilo; + sprintf(suffix, "E"); + } else if (val >= peta) { + val /= tera; + dval = (double)val / kilo; + sprintf(suffix, "P"); + } else if (val >= tera) { + val /= giga; + dval = (double)val / kilo; + sprintf(suffix, "T"); + } else if (val >= giga) { + val /= mega; + dval = (double)val / kilo; + sprintf(suffix, "G"); + } else if (val >= mega) { + val /= kilo; + dval = (double)val / kilo; + sprintf(suffix, "M"); + } else if (val >= kilo) { + dval = (double)val / kilo; + sprintf(suffix, "K"); + } else + dval = val; + + if (!sigdigits) + sprintf(buf, "%d%s", (unsigned int)dval, suffix); + else + sprintf(buf, "%.*g%s", sigdigits, dval, suffix); +} + static void get_statline(char *buf, struct cgpu_info *cgpu) { double displayed_hashes, displayed_rolling = cgpu->rolling; @@ -1929,6 +1974,26 @@ share_result(json_t *val, json_t *res, json_t *err, const struct work *work, } } +static uint64_t share_diff(const struct work *work) +{ + const uint64_t h64 = 0xFFFF000000000000ull; + char rtarget[33], *target; + uint64_t *data64, d64; + uint64_t ret; + + target = bin2hex(work->hash, 32); + if (unlikely(!target)) + quit(1, "Failed to bin2hex in share_diff"); + swab256(rtarget, target); + free(target); + data64 = (uint64_t *)(rtarget + 4); + d64 = be64toh(*data64); + if (unlikely(!d64)) + d64 = 1; + ret = h64 / d64; + return ret; +} + static bool submit_upstream_work(const struct work *work, CURL *curl, bool resubmit) { char *hexstr = NULL; @@ -1991,8 +2056,12 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub sprintf(hashshow, "%08lx.%08lx", (unsigned long)(hash32[7]), (unsigned long)(hash32[6])); else { int intdiff = round(work->work_difficulty); + uint64_t sharediff = share_diff(work); + char diffdisp[16]; + + suffix_string(sharediff, diffdisp, 0); - sprintf(hashshow, "%08lx Diff %d%s", (unsigned long)(hash32[6]), intdiff, + sprintf(hashshow, "%08lx Diff %s/%d%s", (unsigned long)(hash32[6]), diffdisp, intdiff, work->block? " BLOCK!" : ""); } @@ -4079,13 +4148,16 @@ static void stratum_share_result(json_t *val, json_t *res_val, json_t *err_val, struct stratum_share *sshare) { struct work *work = &sshare->work; + uint64_t sharediff = share_diff(work); char hashshow[65]; uint32_t *hash32; + char diffdisp[16]; int intdiff; hash32 = (uint32_t *)(work->hash); intdiff = round(work->work_difficulty); - sprintf(hashshow, "%08lx Diff %d%s", (unsigned long)(hash32[6]), intdiff, + suffix_string(sharediff, diffdisp, 0); + sprintf(hashshow, "%08lx Diff %s/%d%s", (unsigned long)(hash32[6]), diffdisp, intdiff, work->block? " BLOCK!" : ""); share_result(val, res_val, err_val, work, hashshow, false, ""); } diff --git a/miner.h b/miner.h index 3a65d755..5e982447 100644 --- a/miner.h +++ b/miner.h @@ -144,10 +144,12 @@ static inline int fsync (int fd) #ifndef htobe32 # if __BYTE_ORDER == __LITTLE_ENDIAN # 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 be32toh(x) (x) +# define be64toh(x) (x) # define htobe32(x) (x) # define htobe64(x) (x) #else From 911b1788c72d47e0b11fedb2b26f047dfae05369 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 12 Oct 2012 14:40:02 +1100 Subject: [PATCH 149/160] Use the suffix string function for displaying hashrate with 4 significant digits. --- cgminer.c | 52 +++++++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/cgminer.c b/cgminer.c index cd2c31ba..4dfeef42 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1476,6 +1476,7 @@ void tailsprintf(char *f, const char *fmt, ...) * associated suitable for Mega, Giga etc. Buf array needs to be long enough */ static void suffix_string(uint64_t val, char *buf, int sigdigits) { + const double dkilo = 1000.0; const uint64_t kilo = 1000ull; const uint64_t mega = 1000000ull; const uint64_t giga = 1000000000ull; @@ -1487,26 +1488,26 @@ static void suffix_string(uint64_t val, char *buf, int sigdigits) if (val >= exa) { val /= peta; - dval = (double)val / kilo; + dval = (double)val / dkilo; sprintf(suffix, "E"); } else if (val >= peta) { val /= tera; - dval = (double)val / kilo; + dval = (double)val / dkilo; sprintf(suffix, "P"); } else if (val >= tera) { val /= giga; - dval = (double)val / kilo; + dval = (double)val / dkilo; sprintf(suffix, "T"); } else if (val >= giga) { val /= mega; - dval = (double)val / kilo; + dval = (double)val / dkilo; sprintf(suffix, "G"); } else if (val >= mega) { val /= kilo; - dval = (double)val / kilo; + dval = (double)val / dkilo; sprintf(suffix, "M"); } else if (val >= kilo) { - dval = (double)val / kilo; + dval = (double)val / dkilo; sprintf(suffix, "K"); } else dval = val; @@ -1519,26 +1520,25 @@ static void suffix_string(uint64_t val, char *buf, int sigdigits) static void get_statline(char *buf, struct cgpu_info *cgpu) { - double displayed_hashes, displayed_rolling = cgpu->rolling; - bool mhash_base = true; + char displayed_hashes[16], displayed_rolling[16]; + uint64_t dh64, dr64; - displayed_hashes = cgpu->total_mhashes / total_secs; - if (displayed_hashes < 1) { - displayed_hashes *= 1000; - displayed_rolling *= 1000; - mhash_base = false; - } + dh64 = cgpu->total_mhashes / total_secs; + dh64 *= 1000000ull; + dr64 = cgpu->rolling; + dr64 *= 1000000ull; + suffix_string(dh64, displayed_hashes, 4); + suffix_string(dr64, displayed_rolling, 4); sprintf(buf, "%s%d ", cgpu->api->name, cgpu->device_id); if (cgpu->api->get_statline_before) cgpu->api->get_statline_before(buf, cgpu); else tailsprintf(buf, " | "); - tailsprintf(buf, "(%ds):%.1f (avg):%.1f %sh/s | A:%d R:%d HW:%d U:%.1f/m", + tailsprintf(buf, "(%ds):%s (avg):%sh/s | A:%d R:%d HW:%d U:%.1f/m", opt_log_interval, displayed_rolling, displayed_hashes, - mhash_base ? "M" : "K", cgpu->accepted, cgpu->rejected, cgpu->hw_errors, @@ -4038,9 +4038,10 @@ static void hashmeter(int thr_id, struct timeval *diff, double utility, efficiency = 0.0; static double local_mhashes_done = 0; static double rolling = 0; - double local_mhashes, displayed_hashes, displayed_rolling; - bool mhash_base = true; + double local_mhashes; bool showlog = false; + char displayed_hashes[16], displayed_rolling[16]; + uint64_t dh64, dr64; local_mhashes = (double)hashes_done / 1000000.0; /* Update the last time this thread reported in */ @@ -4118,17 +4119,14 @@ static void hashmeter(int thr_id, struct timeval *diff, utility = total_accepted / total_secs * 60; efficiency = total_getworks ? total_accepted * 100.0 / total_getworks : 0.0; - displayed_hashes = total_mhashes_done / total_secs; - displayed_rolling = rolling; - if (displayed_hashes < 1) { - displayed_hashes *= 1000; - displayed_rolling *= 1000; - mhash_base = false; - } + dh64 = (double)total_mhashes_done / total_secs * 1000000ull; + dr64 = (double)rolling * 1000000ull; + suffix_string(dh64, displayed_hashes, 4); + suffix_string(dr64, displayed_rolling, 4); - sprintf(statusline, "%s(%ds):%.1f (avg):%.1f %sh/s | Q:%d A:%d R:%d HW:%d E:%.0f%% U:%.1f/m", + sprintf(statusline, "%s(%ds):%s (avg):%sh/s | Q:%d A:%d R:%d HW:%d E:%.0f%% U:%.1f/m", want_per_device_stats ? "ALL " : "", - opt_log_interval, displayed_rolling, displayed_hashes, mhash_base ? "M" : "K", + opt_log_interval, displayed_rolling, displayed_hashes, total_getworks, total_accepted, total_rejected, hw_errors, efficiency, utility); From a10e3294bda75cd48b0f26a0429927722eebbb5f Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 12 Oct 2012 14:41:13 +1100 Subject: [PATCH 150/160] Be consistent with the get_statline function. --- cgminer.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cgminer.c b/cgminer.c index 4dfeef42..2baf4263 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1523,10 +1523,8 @@ static void get_statline(char *buf, struct cgpu_info *cgpu) char displayed_hashes[16], displayed_rolling[16]; uint64_t dh64, dr64; - dh64 = cgpu->total_mhashes / total_secs; - dh64 *= 1000000ull; - dr64 = cgpu->rolling; - dr64 *= 1000000ull; + dh64 = (double)total_mhashes_done / total_secs * 1000000ull; + dr64 = (double)rolling * 1000000ull; suffix_string(dh64, displayed_hashes, 4); suffix_string(dr64, displayed_rolling, 4); From 660a0ffe16a43eb2cbca7725071b509b23bf4521 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 12 Oct 2012 14:46:55 +1100 Subject: [PATCH 151/160] Correct variables used in get_statline --- cgminer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index 2baf4263..a01ba56d 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1523,8 +1523,8 @@ static void get_statline(char *buf, struct cgpu_info *cgpu) char displayed_hashes[16], displayed_rolling[16]; uint64_t dh64, dr64; - dh64 = (double)total_mhashes_done / total_secs * 1000000ull; - dr64 = (double)rolling * 1000000ull; + dh64 = (double)cgpu->total_mhashes / total_secs * 1000000ull; + dr64 = (double)cgpu->rolling * 1000000ull; suffix_string(dh64, displayed_hashes, 4); suffix_string(dr64, displayed_rolling, 4); From c3bdb359d5ec65006286acb22f45608947f92047 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 12 Oct 2012 14:52:14 +1100 Subject: [PATCH 152/160] Use the suffix string function when displaying device hashrates. --- cgminer.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/cgminer.c b/cgminer.c index a01ba56d..666cbe90 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1608,9 +1608,9 @@ static void curses_print_devstatus(int thr_id) { static int awidth = 1, rwidth = 1, hwwidth = 1, uwidth = 1; struct cgpu_info *cgpu = thr_info[thr_id].cgpu; - double displayed_hashes, displayed_rolling; - bool mhash_base = true; char logline[255]; + char displayed_hashes[16], displayed_rolling[16]; + uint64_t dh64, dr64; if (devcursor + cgpu->cgminer_id > LINES - 2) return; @@ -1627,13 +1627,10 @@ static void curses_print_devstatus(int thr_id) else wprintw(statuswin, " | "); - displayed_hashes = cgpu->total_mhashes / total_secs; - displayed_rolling = cgpu->rolling; - if (displayed_hashes < 1) { - displayed_hashes *= 1000; - displayed_rolling *= 1000; - mhash_base = false; - } + dh64 = (double)cgpu->total_mhashes / total_secs * 1000000ull; + dr64 = (double)cgpu->rolling * 1000000ull; + suffix_string(dh64, displayed_hashes, 4); + suffix_string(dr64, displayed_rolling, 4); if (cgpu->status == LIFE_DEAD) wprintw(statuswin, "DEAD "); @@ -1644,15 +1641,14 @@ static void curses_print_devstatus(int thr_id) else if (cgpu->deven == DEV_RECOVER) wprintw(statuswin, "REST "); else - wprintw(statuswin, "%5.1f", displayed_rolling); + wprintw(statuswin, "%6s", displayed_rolling); adj_width(cgpu->accepted, &awidth); adj_width(cgpu->rejected, &rwidth); adj_width(cgpu->hw_errors, &hwwidth); adj_width(cgpu->utility, &uwidth); - wprintw(statuswin, "/%5.1f%sh/s | A:%*d R:%*d HW:%*d U:%*.2f/m", + wprintw(statuswin, "/%6sh/s | A:%*d R:%*d HW:%*d U:%*.2f/m", displayed_hashes, - mhash_base ? "M" : "K", awidth, cgpu->accepted, rwidth, cgpu->rejected, hwwidth, cgpu->hw_errors, From 7c7e51166b54dd47b090e82512f1a6086f4a6939 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 12 Oct 2012 14:53:16 +1100 Subject: [PATCH 153/160] Disable stratum detection with scrypt. --- cgminer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cgminer.c b/cgminer.c index 666cbe90..8606c8f7 100644 --- a/cgminer.c +++ b/cgminer.c @@ -565,6 +565,9 @@ static char *set_rr(enum pool_strategy *strategy) * stratum+tcp or by detecting a stratum server response */ bool detect_stratum(struct pool *pool, char *url) { + if (opt_scrypt) + return false; + if (!extract_sockaddr(pool, url)) return false; From 9ccfcee6dce1a3d46ec9bc2bf71ca7c5076f2038 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 12 Oct 2012 14:55:52 +1100 Subject: [PATCH 154/160] Prevent overflows of the port char array in extract_sockaddr. --- util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util.c b/util.c index 91a67182..2fb86678 100644 --- a/util.c +++ b/util.c @@ -832,7 +832,7 @@ bool extract_sockaddr(struct pool *pool, char *url) sprintf(url_address, "%.*s", url_len, url_begin); if (port_len) - sprintf(port, "%.*s", port_len, port_start); + snprintf(port, 5, "%.*s", port_len, port_start); else strcpy(port, "80"); From fc72ad55632dbdce81d00f2a5dbd380204972606 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 12 Oct 2012 14:57:42 +1100 Subject: [PATCH 155/160] Off by one error. --- util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util.c b/util.c index 2fb86678..fe9501c6 100644 --- a/util.c +++ b/util.c @@ -832,7 +832,7 @@ bool extract_sockaddr(struct pool *pool, char *url) sprintf(url_address, "%.*s", url_len, url_begin); if (port_len) - snprintf(port, 5, "%.*s", port_len, port_start); + snprintf(port, 6, "%.*s", port_len, port_start); else strcpy(port, "80"); From 6cebabea9a2f15bababb68eaa39911b94c06ea58 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 12 Oct 2012 15:40:18 +1100 Subject: [PATCH 156/160] Update readme describing difficulty displayed on log lines. --- README | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README b/README index 0d17e8af..c8619f76 100644 --- a/README +++ b/README @@ -382,6 +382,18 @@ Thread 1: 60.2 Mh/s Enabled ALIVE Or press any other key to continue +The running log shows output like this: + + [2012-10-12 15:38:17] Accepted 78bb4861 Diff 2/1 GPU 1 pool 6 + [2012-10-12 15:38:17] Accepted f99b2b7a Diff 4/1 GPU 2 pool 6 + [2012-10-12 15:38:23] Accepted af298bef Diff 4/1 GPU 0 pool 6 + [2012-10-12 15:38:24] Accepted d04421af Diff 5/1 GPU 0 pool 6 + [2012-10-12 15:38:25] Accepted c18e5b5b Diff 4/1 GPU 3 pool 6 + +The 8 byte hex value are the 2nd 8 bytes of the share being submitted to the +pool. The 2 diff values are the actual difficulty target that share reached +followed by the difficulty target the pool is currently asking for. + --- Also many issues and FAQs are covered in the forum thread dedicated to this program, From f22fe7615717aed3c085eb4ffc11005084bbff9b Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 12 Oct 2012 17:36:48 +1100 Subject: [PATCH 157/160] Share_diff should not be converting the work data to hex. --- cgminer.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/cgminer.c b/cgminer.c index 8606c8f7..31ebf42a 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1974,16 +1974,12 @@ share_result(json_t *val, json_t *res, json_t *err, const struct work *work, static uint64_t share_diff(const struct work *work) { const uint64_t h64 = 0xFFFF000000000000ull; - char rtarget[33], *target; uint64_t *data64, d64; + char rhash[33]; uint64_t ret; - target = bin2hex(work->hash, 32); - if (unlikely(!target)) - quit(1, "Failed to bin2hex in share_diff"); - swab256(rtarget, target); - free(target); - data64 = (uint64_t *)(rtarget + 4); + swab256(rhash, work->hash); + data64 = (uint64_t *)(rhash + 4); d64 = be64toh(*data64); if (unlikely(!d64)) d64 = 1; From 13676ef11ac04cbee308c0c6eb388a4a5271e8d6 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 12 Oct 2012 18:00:14 +1100 Subject: [PATCH 158/160] Left align values that are suffix_string generated. --- cgminer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 31ebf42a..b55aed95 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1518,7 +1518,7 @@ static void suffix_string(uint64_t val, char *buf, int sigdigits) if (!sigdigits) sprintf(buf, "%d%s", (unsigned int)dval, suffix); else - sprintf(buf, "%.*g%s", sigdigits, dval, suffix); + sprintf(buf, "%-*.*g%s", sigdigits + 1, sigdigits, dval, suffix); } static void get_statline(char *buf, struct cgpu_info *cgpu) From b976261c4e756640d85639031c07c2fe9d6ab744 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 12 Oct 2012 18:05:40 +1100 Subject: [PATCH 159/160] Update documentation. --- NEWS | 18 ++++++++++++++++++ README | 9 ++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index 4b154853..ac6e4a56 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,21 @@ +Version 2.8.3 - October 12, 2012 + +- Left align values that are suffix_string generated. +- Share_diff should not be converting the work data to hex. +- Off by one error. +- Prevent overflows of the port char array in extract_sockaddr. +- Disable stratum detection with scrypt. +- Use the suffix string function when displaying device hashrates. +- Be consistent with the get_statline function. +- Use the suffix string function for displaying hashrate with 4 significant +digits. +- Display the actual share diff next to the pool required diff, using a suffix +creation function to prevent values of >1000 being shown in their entirety. +- Fix 4 * 0 being 0 that would break dynamic intensity mode. +- Fix wrong byteswap macro being used on mingw32 which was breaking target +generation on stratum. + + Version 2.8.2 - October 11, 2012 - Reinstate the history on dynamic intensity mode to damp fluctuations in diff --git a/README b/README index c8619f76..5dc33695 100644 --- a/README +++ b/README @@ -384,11 +384,10 @@ Or press any other key to continue The running log shows output like this: - [2012-10-12 15:38:17] Accepted 78bb4861 Diff 2/1 GPU 1 pool 6 - [2012-10-12 15:38:17] Accepted f99b2b7a Diff 4/1 GPU 2 pool 6 - [2012-10-12 15:38:23] Accepted af298bef Diff 4/1 GPU 0 pool 6 - [2012-10-12 15:38:24] Accepted d04421af Diff 5/1 GPU 0 pool 6 - [2012-10-12 15:38:25] Accepted c18e5b5b Diff 4/1 GPU 3 pool 6 + [2012-10-12 18:02:20] Accepted f0c05469 Diff 1/1 GPU 0 pool 1 + [2012-10-12 18:02:22] Accepted 218ac982 Diff 7/1 GPU 1 pool 1 + [2012-10-12 18:02:23] Accepted d8300795 Diff 1/1 GPU 3 pool 1 + [2012-10-12 18:02:24] Accepted 122c1ff1 Diff 14/1 GPU 1 pool 1 The 8 byte hex value are the 2nd 8 bytes of the share being submitted to the pool. The 2 diff values are the actual difficulty target that share reached From a63fc8c25c2b121f0c6d7b19b4957c5f87eded9a Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 12 Oct 2012 18:06:00 +1100 Subject: [PATCH 160/160] Bump version to 2.8.3 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 03583f3a..0d77b979 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## m4_define([v_maj], [2]) m4_define([v_min], [8]) -m4_define([v_mic], [2]) +m4_define([v_mic], [3]) ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## m4_define([v_ver], [v_maj.v_min.v_mic]) m4_define([lt_rev], m4_eval(v_maj + v_min))