diff --git a/miner.h b/miner.h index 7db088fd..be1be447 100644 --- a/miner.h +++ b/miner.h @@ -1078,6 +1078,7 @@ extern int nDevs; extern int hw_errors; extern bool use_syslog; extern bool opt_quiet; +extern bool opt_extranonce_subscribe; extern struct thr_info *control_thr; extern struct thr_info **mining_thr; extern struct cgpu_info gpus[MAX_GPUDEVICES]; diff --git a/sgminer.c b/sgminer.c index 980b4e39..4b3bf7cf 100644 --- a/sgminer.c +++ b/sgminer.c @@ -151,6 +151,7 @@ bool opt_api_network; bool opt_delaynet; bool opt_disable_pool; bool opt_disable_client_reconnect = false; +bool opt_extranonce_subscribe = true; static bool no_work; bool opt_worktime; #if defined(HAVE_LIBCURL) && defined(CURL_HAS_KEEPALIVE) @@ -1327,6 +1328,9 @@ static struct opt_table opt_config_table[] = { OPT_WITHOUT_ARG("--no-submit-stale", opt_set_invbool, &opt_submit_stale, "Don't submit shares if they are detected as stale"), + OPT_WITHOUT_ARG("--no-extranonce-subscribe", + opt_set_invbool, &opt_extranonce_subscribe, + "Disable 'extranonce' stratum subscribe"), OPT_WITH_ARG("--pass|-p", set_pass, NULL, NULL, "Password for bitcoin JSON-RPC server"), @@ -5204,6 +5208,15 @@ static bool parse_stratum_response(struct pool *pool, char *s) id = json_integer_value(id_val); + if (err_val && !json_is_null(err_val)) { + char *ss; + ss = (char *)json_string_value(json_array_get(err_val, 1)); + if (opt_extranonce_subscribe && strcmp(ss, "Method 'subscribe' not found for service 'mining.extranonce'") == 0) { + applog(LOG_INFO, "Cannot subscribe to mining.extranonce on %s", get_pool_name(pool)); + goto out; + } + } + mutex_lock(&sshare_lock); HASH_FIND_INT(stratum_shares, &id, sshare); if (sshare) { @@ -5673,7 +5686,7 @@ retry_stratum: bool init = pool_tset(pool, &pool->stratum_init); if (!init) { - bool ret = initiate_stratum(pool) && auth_stratum(pool); + bool ret = initiate_stratum(pool) && (!opt_extranonce_subscribe || subscribe_extranonce(pool)) && auth_stratum(pool); if (ret) init_stratum_threads(pool); diff --git a/util.c b/util.c index 128a0479..85557f13 100644 --- a/util.c +++ b/util.c @@ -1664,6 +1664,39 @@ static bool parse_diff(struct pool *pool, json_t *val) return true; } +static bool parse_extranonce(struct pool *pool, json_t *val) +{ + char s[RBUFSIZE], *nonce1; + int n2size; + + nonce1 = json_array_string(val, 0); + if (!nonce1) { +// applog(LOG_INFO, "Failed to get nonce1 in "); + return false; + } + n2size = json_integer_value(json_array_get(val, 1)); + if (!n2size) { +// applog(LOG_INFO, "Failed to get n2size in "); + free(nonce1); + return false; + } + + cg_wlock(&pool->data_lock); + pool->nonce1 = nonce1; + pool->n1_len = strlen(nonce1) / 2; + free(pool->nonce1bin); + pool->nonce1bin = (unsigned char *)calloc(pool->n1_len, 1); + if (unlikely(!pool->nonce1bin)) + quithere(1, "Failed to calloc pool->nonce1bin"); + hex2bin(pool->nonce1bin, pool->nonce1, pool->n1_len); + pool->n2size = n2size; + cg_wunlock(&pool->data_lock); + + applog(LOG_NOTICE, "%s coin change requested", get_pool_name(pool)); + + return true; +} + static void __suspend_stratum(struct pool *pool) { clear_sockbuf(pool); @@ -1807,6 +1840,12 @@ bool parse_method(struct pool *pool, char *s) return ret; } + if (!strncasecmp(buf, "mining.set_extranonce", 21) && parse_extranonce(pool, params)) { + ret = true; + json_decref(val); + return ret; + } + if (!strncasecmp(buf, "client.reconnect", 16) && parse_reconnect(pool, params)) { ret = true; json_decref(val); @@ -1828,6 +1867,70 @@ bool parse_method(struct pool *pool, char *s) return ret; } +bool subscribe_extranonce(struct pool *pool) +{ + json_t *val = NULL, *res_val, *err_val; + char s[RBUFSIZE], *sret = NULL; + json_error_t err; + bool ret = false; + + sprintf(s, "{\"id\": %d, \"method\": \"mining.extranonce.subscribe\", \"params\": []}", + swork_id++); + + if (!stratum_send(pool, s, strlen(s))) + return ret; + + /* Parse all data in the queue and anything left should be auth */ + while (42) { + if (!socket_full(pool, DEFAULT_SOCKWAIT / 30)) { + applog(LOG_DEBUG, "Timed out waiting for response extranonce.subscribe"); + /* some pool doesnt send anything, so this is normal */ + ret = true; + goto out; + } + + sret = recv_line(pool); + if (!sret) + return ret; + if (parse_method(pool, sret)) + free(sret); + else + break; + } + + 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 = (char *)json_string_value(json_array_get(err_val, 1)); + if (opt_extranonce_subscribe && strcmp(ss, "Method 'subscribe' not found for service 'mining.extranonce'") == 0) { + applog(LOG_INFO, "Cannot subscribe to mining.extranonce on %s", get_pool_name(pool)); + ret = true; + goto out; + } + ss = json_dumps(err_val, JSON_INDENT(3)); + } + else + ss = strdup("(unknown reason)"); + applog(LOG_INFO, "%s JSON stratum auth failed: %s", get_pool_name(pool), ss); + free(ss); + + goto out; + } + + ret = true; + applog(LOG_INFO, "Stratum extranonce subscribe for %s", get_pool_name(pool)); + +out: + json_decref(val); + return ret; +} + bool auth_stratum(struct pool *pool) { json_t *val = NULL, *res_val, *err_val; @@ -2458,6 +2561,8 @@ bool restart_stratum(struct pool *pool) suspend_stratum(pool); if (!initiate_stratum(pool)) return false; + if (opt_extranonce_subscribe && !subscribe_extranonce(pool)) + return false; if (!auth_stratum(pool)) return false;