diff --git a/configure.ac b/configure.ac index 74b4c1039..63777cbdf 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([cpuminer], [2.5.1]) +AC_INIT([cpuminer], [2.5.1-maxdiff]) AC_PREREQ([2.59c]) AC_CANONICAL_SYSTEM diff --git a/cpu-miner.c b/cpu-miner.c index 46db161a7..84b046028 100644 --- a/cpu-miner.c +++ b/cpu-miner.c @@ -86,7 +86,7 @@ static inline void affine_to_cpu(int id, int cpu) { } #endif - + enum workio_commands { WC_GET_WORK, WC_SUBMIT_WORK, @@ -146,6 +146,8 @@ int longpoll_thr_id = -1; int stratum_thr_id = -1; struct work_restart *work_restart = NULL; static struct stratum_ctx stratum; +static double max_diff = 0.; +static int max_diff_backoff_secs = 10; pthread_mutex_t applog_lock; static pthread_mutex_t stats_lock; @@ -192,6 +194,11 @@ Options:\n\ --no-gbt disable getblocktemplate support\n\ --no-stratum disable X-Stratum support\n\ --no-redirect ignore requests to change the URL of the mining server\n\ + -M, --max-diff=N[:T] specify a floating point value for the maximum block\n\ + difficulty that we will mine (default: inf); this\n\ + option is intended for testnet miners wishing to only\n\ + mine when difficulty drops to 1.0 (optional :T is the\n\ + time to sleep in seconds, default: 10)\n\ -q, --quiet disable per-thread hashmeter output\n\ -D, --debug enable debug output\n\ -P, --protocol-dump verbose dump of protocol-level activities\n" @@ -217,7 +224,7 @@ static char const short_options[] = #ifdef HAVE_SYSLOG_H "S" #endif - "a:c:Dhp:Px:qr:R:s:t:T:o:u:O:V"; + "a:c:DhM:p:Px:qr:R:s:t:T:o:u:O:V"; static struct option const options[] = { { "algo", 1, NULL, 'a' }, @@ -236,6 +243,7 @@ static struct option const options[] = { { "no-longpoll", 0, NULL, 1003 }, { "no-redirect", 0, NULL, 1009 }, { "no-stratum", 0, NULL, 1007 }, + { "max-diff", 1, NULL, 'M' }, { "pass", 1, NULL, 'p' }, { "protocol-dump", 0, NULL, 'P' }, { "proxy", 1, NULL, 'x' }, @@ -673,7 +681,7 @@ static void share_result(int result, const char *reason) hashrate += thr_hashrates[i]; result ? accepted_count++ : rejected_count++; pthread_mutex_unlock(&stats_lock); - + sprintf(s, hashrate >= 1e6 ? "%.0f" : "%.2f", 1e-3 * hashrate); applog(LOG_INFO, "accepted: %lu/%lu (%.2f%%), %s khash/s %s", accepted_count, @@ -1028,7 +1036,7 @@ static bool get_work(struct thr_info *thr, struct work *work) static bool submit_work(struct thr_info *thr, const struct work *work_in) { struct workio_cmd *wc; - + /* fill out work request message */ wc = calloc(1, sizeof(*wc)); if (!wc) @@ -1072,7 +1080,7 @@ static void stratum_gen_work(struct stratum_ctx *sctx, struct work *work) memcpy(merkle_root + 32, sctx->job.merkle[i], 32); sha256d(merkle_root, merkle_root, 64); } - + /* Increment extranonce2 */ for (i = 0; i < sctx->xnonce2_size && !++sctx->job.xnonce2[i]; i++); @@ -1130,7 +1138,7 @@ static void *miner_thread(void *userdata) thr_id, thr_id % num_processors); affine_to_cpu(thr_id, thr_id % num_processors); } - + if (opt_algo == ALGO_SCRYPT) { scratchbuf = scrypt_buffer_alloc(opt_scrypt_n); if (!scratchbuf) { @@ -1145,6 +1153,7 @@ static void *miner_thread(void *userdata) struct timeval tv_start, tv_end, diff; int64_t max64; int rc; + double work_diff; if (have_stratum) { while (time(NULL) >= g_work_time + 120) @@ -1181,7 +1190,7 @@ static void *miner_thread(void *userdata) work.data[19]++; pthread_mutex_unlock(&g_work_lock); work_restart[thr_id].restart = 0; - + /* adjust max_nonce to meet target scan time */ if (have_stratum) max64 = LP_SCANTIME; @@ -1203,25 +1212,32 @@ static void *miner_thread(void *userdata) max_nonce = end_nonce; else max_nonce = work.data[19] + max64; - + hashes_done = 0; gettimeofday(&tv_start, NULL); - /* scan nonces for a proof-of-work hash */ - switch (opt_algo) { - case ALGO_SCRYPT: - rc = scanhash_scrypt(thr_id, work.data, scratchbuf, work.target, - max_nonce, &hashes_done, opt_scrypt_n); - break; + if (max_diff > 1.0 && (work_diff = diff_from_nbits(&work.data[18])) > max_diff) { + rc = 0; + applog(LOG_INFO, "thread %d: %1.1lf > max_diff %1.1lf, sleeping %d secs", + thr_id, work_diff, max_diff, max_diff_backoff_secs); + sleep(max_diff_backoff_secs); + } else { + /* scan nonces for a proof-of-work hash */ + switch (opt_algo) { + case ALGO_SCRYPT: + rc = scanhash_scrypt(thr_id, work.data, scratchbuf, work.target, + max_nonce, &hashes_done, opt_scrypt_n); + break; - case ALGO_SHA256D: - rc = scanhash_sha256d(thr_id, work.data, work.target, - max_nonce, &hashes_done); - break; + case ALGO_SHA256D: + rc = scanhash_sha256d(thr_id, work.data, work.target, + max_nonce, &hashes_done); + break; - default: - /* should never happen */ - goto out; + default: + /* should never happen */ + goto out; + } } /* record scanhash elapsed time */ @@ -1291,7 +1307,7 @@ static void *longpoll_thread(void *userdata) lp_url = hdr_path; hdr_path = NULL; } - + /* absolute path, on current server */ else { copy_start = (*hdr_path == '/') ? (hdr_path + 1) : hdr_path; @@ -1445,7 +1461,7 @@ static void *stratum_thread(void *userdata) restart_threads(); } } - + if (!stratum_socket_full(&stratum, 120)) { applog(LOG_ERR, "Stratum connection timed out"); s = NULL; @@ -1757,6 +1773,24 @@ static void parse_arg(int key, char *arg, char *pname) } strcpy(coinbase_sig, arg); break; + case 'M': { /* --max-diff */ + char *colon; + if (sscanf(arg, "%lf", &max_diff) != 1 || max_diff <= 1.0) { + fprintf(stderr, "%s: invalid --max-diff: %s\n", pname, arg); + show_usage_and_exit(1); + } + // Optional second component to arg e.g. "10.0:5" where 5 here + // is the time to sleep. + if ((colon = strchr(arg, ':'))) { + if (sscanf(++colon, "%d", &max_diff_backoff_secs) != 1 + || max_diff_backoff_secs < 1) { + fprintf(stderr, "%s: invalid backoff time specified for" + " --max-diff: %s\n", pname, colon); + show_usage_and_exit(1); + } + } + break; + } case 'S': use_syslog = true; break; @@ -1931,7 +1965,7 @@ int main(int argc, char *argv[]) thr_info = calloc(opt_n_threads + 3, sizeof(*thr)); if (!thr_info) return 1; - + thr_hashrates = (double *) calloc(opt_n_threads, sizeof(double)); if (!thr_hashrates) return 1; diff --git a/miner.h b/miner.h index 3f9b2f440..633b84b0a 100644 --- a/miner.h +++ b/miner.h @@ -206,6 +206,8 @@ extern int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y); extern bool fulltest(const uint32_t *hash, const uint32_t *target); extern void diff_to_target(uint32_t *target, double diff); +/* Return the network difficulty from the work.data[18] bits as a double. */ +extern double diff_from_nbits(const void *nbits); struct stratum_job { char *job_id; diff --git a/util.c b/util.c index 40d5f4c83..1e0b0726f 100644 --- a/util.c +++ b/util.c @@ -74,7 +74,7 @@ void applog(int prio, const char *fmt, ...) va_list ap2; char *buf; int len; - + va_copy(ap2, ap); len = vsnprintf(NULL, 0, fmt, ap2) + 1; va_end(ap2); @@ -794,7 +794,7 @@ bool fulltest(const uint32_t *hash, const uint32_t *target) { int i; bool rc = true; - + for (i = 7; i >= 0; i--) { if (hash[i] > target[i]) { rc = false; @@ -809,7 +809,7 @@ bool fulltest(const uint32_t *hash, const uint32_t *target) if (opt_debug) { uint32_t hash_be[8], target_be[8]; char hash_str[65], target_str[65]; - + for (i = 0; i < 8; i++) { be32enc(hash_be + i, hash[7 - i]); be32enc(target_be + i, target[7 - i]); @@ -831,7 +831,7 @@ void diff_to_target(uint32_t *target, double diff) { uint64_t m; int k; - + for (k = 6; k > 0 && diff > 1.0; k--) diff /= 4294967296.0; m = 4294901760.0 / diff; @@ -844,6 +844,25 @@ void diff_to_target(uint32_t *target, double diff) } } +double diff_from_nbits(const void *nbits_in) +{ + double numerator; + uint32_t diff32; + uint8_t pow; + int powdiff; + const uint32_t possibly_unswabbed_bits = le32dec(nbits_in); + const uint8_t * const nbits = (const uint8_t *)&possibly_unswabbed_bits; + + pow = nbits[0]; + powdiff = (8 * (0x1d - 3)) - (8 * (pow - 3)); + if (powdiff < 0) // testnet only + powdiff = 0; + diff32 = be32dec(nbits) & 0x00FFFFFF; + numerator = 0xFFFFULL << powdiff; + + return numerator / (double)diff32; +} + #ifdef WIN32 #define socket_blocks() (WSAGetLastError() == WSAEWOULDBLOCK) #else @@ -853,7 +872,7 @@ void diff_to_target(uint32_t *target, double diff) static bool send_line(struct stratum_ctx *sctx, char *s) { ssize_t len, sent = 0; - + len = strlen(s); s[len++] = '\n'; @@ -1412,7 +1431,7 @@ static bool stratum_get_version(struct stratum_ctx *sctx, json_t *id) char *s; json_t *val; bool ret; - + if (!id || json_is_null(id)) return false; @@ -1437,7 +1456,7 @@ static bool stratum_show_message(struct stratum_ctx *sctx, json_t *id, json_t *p val = json_array_get(params, 0); if (val) applog(LOG_NOTICE, "MESSAGE FROM SERVER: %s", json_string_value(val)); - + if (!id || json_is_null(id)) return true;