Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a new CLI option -M or --max-diff for limiting mining to low-difficulty periods #199

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 58 additions & 24 deletions cpu-miner.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ static inline void affine_to_cpu(int id, int cpu)
{
}
#endif

enum workio_commands {
WC_GET_WORK,
WC_SUBMIT_WORK,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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"
Expand All @@ -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' },
Expand All @@ -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' },
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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++);

Expand Down Expand Up @@ -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) {
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions miner.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
33 changes: 26 additions & 7 deletions util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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]);
Expand All @@ -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;
Expand All @@ -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
Expand All @@ -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';

Expand Down Expand Up @@ -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;

Expand All @@ -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;

Expand Down