From 70743eb48dde298d90b942c7b8515dbe7bb025d2 Mon Sep 17 00:00:00 2001 From: Tanguy Pruvot Date: Sun, 7 Dec 2014 16:44:59 +0100 Subject: [PATCH] solo: get bloc height and trap more errors and disable multiple nonce on wallets, a bloc cant be resolved twice ;) Signed-off-by: Tanguy Pruvot --- ccminer.cpp | 87 ++++++++++++++++++++++++++++++++++++++++++++++------- util.cpp | 39 ++++++++++++++++++------ 2 files changed, 106 insertions(+), 20 deletions(-) diff --git a/ccminer.cpp b/ccminer.cpp index b0f2b9a..f33aa54 100644 --- a/ccminer.cpp +++ b/ccminer.cpp @@ -192,6 +192,7 @@ bool want_longpoll = true; bool have_longpoll = false; bool want_stratum = true; bool have_stratum = false; +bool allow_gbt = true; static bool submit_old = false; bool use_syslog = false; bool use_colors = true; @@ -661,6 +662,55 @@ static bool submit_upstream_work(CURL *curl, struct work *work) return true; } +/* simplified method to only get some extra infos in solo mode */ +static bool gbt_work_decode(const json_t *val, struct work *work) +{ + json_t *err = json_object_get(val, "error"); + if (err && !json_is_null(err)) { + allow_gbt = false; + applog(LOG_INFO, "GBT not supported, bloc height unavailable"); + return false; + } + + if (!work->height) { + // complete missing data from getwork + json_t *key = json_object_get(val, "height"); + if (key && json_is_integer(key)) { + work->height = (uint32_t) json_integer_value(key); + if (!opt_quiet && work->height != g_work.height) { + applog(LOG_BLUE, "%s %s block %d", short_url, + algo_names[opt_algo], work->height); + } + } + } + + return true; +} + +#define GBT_CAPABILITIES "[\"coinbasetxn\", \"coinbasevalue\", \"longpoll\", \"workid\"]" +static const char *gbt_req = + "{\"method\": \"getblocktemplate\", \"params\": [" + // "{\"capabilities\": " GBT_CAPABILITIES "}" + "], \"id\":0}\r\n"; + +static bool get_blocktemplate(CURL *curl, struct work *work) +{ + if (!allow_gbt) + return false; + + json_t *val = json_rpc_call(curl, rpc_url, rpc_userpass, gbt_req, + want_longpoll, false, NULL); + + if (!val) + return false; + + bool rc = gbt_work_decode(json_object_get(val, "result"), work); + + json_decref(val); + + return rc; +} + static const char *rpc_req = "{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n"; @@ -695,6 +745,8 @@ static bool get_upstream_work(CURL *curl, struct work *work) json_decref(val); + get_blocktemplate(curl, work); + return rc; } @@ -985,6 +1037,15 @@ static void stratum_gen_work(struct stratum_ctx *sctx, struct work *work) } } +static void restart_threads(void) +{ + if (opt_debug && !opt_quiet) + applog(LOG_DEBUG,"%s", __FUNCTION__); + + for (int i = 0; i < opt_n_threads; i++) + work_restart[i].restart = 1; +} + static void *miner_thread(void *userdata) { struct thr_info *mythr = (struct thr_info *)userdata; @@ -1063,7 +1124,8 @@ static void *miner_thread(void *userdata) } } - if (!opt_benchmark && memcmp(work.target, g_work.target, sizeof(work.target))) { + if (!opt_benchmark && (g_work.height != work.height || memcmp(work.target, g_work.target, sizeof(work.target)))) + { calc_diff(&g_work, 0); if (!have_stratum) global_diff = g_work.difficulty; @@ -1073,6 +1135,7 @@ static void *miner_thread(void *userdata) } memcpy(work.target, g_work.target, sizeof(work.target)); work.difficulty = g_work.difficulty; + work.height = g_work.height; nonceptr[0] = (UINT32_MAX / opt_n_threads) * thr_id; // 0 if single thr /* on new target, ignoring nonce, clear sent data (hashlog) */ if (memcmp(work.target, g_work.target, sizeof(work.target))) { @@ -1409,7 +1472,18 @@ static void *miner_thread(void *userdata) if (rc && !opt_benchmark) { if (!submit_work(mythr, &work)) break; - // second nonce found, submit too + + // prevent stale work in solo + // we can't submit twice a block! + if (!have_stratum) { + pthread_mutex_lock(&g_work_lock); + // will force getwork + g_work_time = 0; + pthread_mutex_unlock(&g_work_lock); + continue; + } + + // second nonce found, submit too (on pool only!) if (rc > 1 && work.data[21]) { work.data[19] = work.data[21]; work.data[21] = 0; @@ -1427,15 +1501,6 @@ out: return NULL; } -static void restart_threads(void) -{ - if (opt_debug) - applog(LOG_DEBUG,"%s", __FUNCTION__); - - for (int i = 0; i < opt_n_threads; i++) - work_restart[i].restart = 1; -} - static void *longpoll_thread(void *userdata) { struct thr_info *mythr = (struct thr_info *)userdata; diff --git a/util.cpp b/util.cpp index e88f9df..ef9dc0c 100644 --- a/util.cpp +++ b/util.cpp @@ -333,14 +333,15 @@ json_t *json_rpc_call(CURL *curl, const char *url, { json_t *val, *err_val, *res_val; int rc; - struct data_buffer all_data = {0}; + struct data_buffer all_data = { 0 }; struct upload_buffer upload_data; json_error_t err; struct curl_slist *headers = NULL; + char* httpdata; char len_hdr[64], hashrate_hdr[64]; - char curl_err_str[CURL_ERROR_SIZE]; + char curl_err_str[CURL_ERROR_SIZE] = { 0 }; long timeout = longpoll ? opt_timeout : 30; - struct header_info hi = {0}; + struct header_info hi = { 0 }; bool lp_scanning = longpoll_scan && !have_longpoll; /* it is assumed that 'curl' is freshly [re]initialized at this pt */ @@ -351,7 +352,7 @@ json_t *json_rpc_call(CURL *curl, const char *url, if (opt_cert) curl_easy_setopt(curl, CURLOPT_CAINFO, opt_cert); curl_easy_setopt(curl, CURLOPT_ENCODING, ""); - curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); + curl_easy_setopt(curl, CURLOPT_FAILONERROR, 0); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, all_data_cb); @@ -404,9 +405,10 @@ json_t *json_rpc_call(CURL *curl, const char *url, if (curl_err != NULL) *curl_err = rc; if (rc) { - if (!(longpoll && rc == CURLE_OPERATION_TIMEDOUT)) + if (!(longpoll && rc == CURLE_OPERATION_TIMEDOUT)) { applog(LOG_ERR, "HTTP request failed: %s", curl_err_str); - goto err_out; + goto err_out; + } } /* If X-Stratum was found, activate Stratum */ @@ -425,14 +427,27 @@ json_t *json_rpc_call(CURL *curl, const char *url, hi.lp_path = NULL; } - if (!all_data.buf) { + if (!all_data.buf || !all_data.len) { applog(LOG_ERR, "Empty data received in json_rpc_call."); goto err_out; } - val = JSON_LOADS((const char*)all_data.buf, &err); + httpdata = (char*) all_data.buf; + + if (*httpdata != '{' && *httpdata != '[') { + long errcode = 0; + CURLcode c = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &errcode); + if (c == CURLE_OK && errcode == 401) { + applog(LOG_ERR, "You are not authorized, check your login and password."); + goto err_out; + } + } + + val = JSON_LOADS(httpdata, &err); if (!val) { applog(LOG_ERR, "JSON decode failed(%d): %s", err.line, err.text); + if (opt_protocol) + applog(LOG_DEBUG, "%s", httpdata); goto err_out; } @@ -451,8 +466,14 @@ json_t *json_rpc_call(CURL *curl, const char *url, (err_val && !json_is_null(err_val))) { char *s; - if (err_val) + if (err_val) { + json_t *msg = json_object_get(err_val, "message"); s = json_dumps(err_val, JSON_INDENT(3)); + if (json_is_string(msg)) { + free(s); + s = strdup(json_string_value(msg)); + } + } else s = strdup("(unknown reason)");