|
|
@ -326,20 +326,12 @@ err_out: |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool submit_upstream_work(CURL *curl, const struct work *work) |
|
|
|
static bool submit_upstream_work(CURL *curl, char *hexstr) |
|
|
|
{ |
|
|
|
{ |
|
|
|
char *hexstr = NULL; |
|
|
|
|
|
|
|
json_t *val, *res; |
|
|
|
json_t *val, *res; |
|
|
|
char s[345]; |
|
|
|
char s[345]; |
|
|
|
bool rc = false; |
|
|
|
bool rc = false; |
|
|
|
|
|
|
|
|
|
|
|
/* build hex string */ |
|
|
|
|
|
|
|
hexstr = bin2hex(work->data, sizeof(work->data)); |
|
|
|
|
|
|
|
if (unlikely(!hexstr)) { |
|
|
|
|
|
|
|
applog(LOG_ERR, "submit_upstream_work OOM"); |
|
|
|
|
|
|
|
goto out; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* build JSON-RPC request */ |
|
|
|
/* build JSON-RPC request */ |
|
|
|
sprintf(s, |
|
|
|
sprintf(s, |
|
|
|
"{\"method\": \"getwork\", \"params\": [ \"%s\" ], \"id\":1}\r\n", |
|
|
|
"{\"method\": \"getwork\", \"params\": [ \"%s\" ], \"id\":1}\r\n", |
|
|
@ -357,6 +349,9 @@ static bool submit_upstream_work(CURL *curl, const struct work *work) |
|
|
|
|
|
|
|
|
|
|
|
res = json_object_get(val, "result"); |
|
|
|
res = json_object_get(val, "result"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* 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)) { |
|
|
|
if (json_is_true(res)) { |
|
|
|
accepted++; |
|
|
|
accepted++; |
|
|
|
applog(LOG_INFO, "PROOF OF WORK RESULT: true (yay!!!)"); |
|
|
|
applog(LOG_INFO, "PROOF OF WORK RESULT: true (yay!!!)"); |
|
|
@ -370,7 +365,6 @@ static bool submit_upstream_work(CURL *curl, const struct work *work) |
|
|
|
rc = true; |
|
|
|
rc = true; |
|
|
|
|
|
|
|
|
|
|
|
out: |
|
|
|
out: |
|
|
|
free(hexstr); |
|
|
|
|
|
|
|
return rc; |
|
|
|
return rc; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -411,21 +405,29 @@ static void workio_cmd_free(struct workio_cmd *wc) |
|
|
|
free(wc); |
|
|
|
free(wc); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool workio_get_work(struct workio_cmd *wc, CURL *curl) |
|
|
|
static bool workio_get_work(struct workio_cmd *wc) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct work *ret_work; |
|
|
|
struct work *ret_work; |
|
|
|
int failures = 0; |
|
|
|
int failures = 0; |
|
|
|
|
|
|
|
bool ret = false; |
|
|
|
|
|
|
|
CURL *curl; |
|
|
|
|
|
|
|
|
|
|
|
ret_work = calloc(1, sizeof(*ret_work)); |
|
|
|
ret_work = calloc(1, sizeof(*ret_work)); |
|
|
|
if (!ret_work) |
|
|
|
if (!ret_work) |
|
|
|
return false; |
|
|
|
goto out; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
curl = curl_easy_init(); |
|
|
|
|
|
|
|
if (unlikely(!curl)) { |
|
|
|
|
|
|
|
applog(LOG_ERR, "CURL initialization failed"); |
|
|
|
|
|
|
|
return ret; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* obtain new work from bitcoin via JSON-RPC */ |
|
|
|
/* obtain new work from bitcoin via JSON-RPC */ |
|
|
|
while (!get_upstream_work(curl, ret_work)) { |
|
|
|
while (!get_upstream_work(curl, ret_work)) { |
|
|
|
if (unlikely((opt_retries >= 0) && (++failures > opt_retries))) { |
|
|
|
if (unlikely((opt_retries >= 0) && (++failures > opt_retries))) { |
|
|
|
applog(LOG_ERR, "json_rpc_call failed, terminating workio thread"); |
|
|
|
applog(LOG_ERR, "json_rpc_call failed, terminating workio thread"); |
|
|
|
free(ret_work); |
|
|
|
free(ret_work); |
|
|
|
return false; |
|
|
|
goto out; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* pause, then restart work-request loop */ |
|
|
|
/* pause, then restart work-request loop */ |
|
|
@ -434,22 +436,33 @@ static bool workio_get_work(struct workio_cmd *wc, CURL *curl) |
|
|
|
sleep(opt_fail_pause); |
|
|
|
sleep(opt_fail_pause); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ret = true; |
|
|
|
/* send work to requesting thread */ |
|
|
|
/* send work to requesting thread */ |
|
|
|
if (!tq_push(wc->thr->q, ret_work)) |
|
|
|
if (!tq_push(wc->thr->q, ret_work)) |
|
|
|
free(ret_work); |
|
|
|
free(ret_work); |
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
out: |
|
|
|
|
|
|
|
curl_easy_cleanup(curl); |
|
|
|
|
|
|
|
return ret; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool workio_submit_work(struct workio_cmd *wc, CURL *curl) |
|
|
|
static void *submit_thread(void *userdata) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
char *hexstr = (char *)userdata; |
|
|
|
int failures = 0; |
|
|
|
int failures = 0; |
|
|
|
|
|
|
|
CURL *curl; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
curl = curl_easy_init(); |
|
|
|
|
|
|
|
if (unlikely(!curl)) { |
|
|
|
|
|
|
|
applog(LOG_ERR, "CURL initialization failed"); |
|
|
|
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* submit solution to bitcoin via JSON-RPC */ |
|
|
|
/* submit solution to bitcoin via JSON-RPC */ |
|
|
|
while (!submit_upstream_work(curl, wc->u.work)) { |
|
|
|
while (!submit_upstream_work(curl, hexstr)) { |
|
|
|
if (unlikely((opt_retries >= 0) && (++failures > opt_retries))) { |
|
|
|
if (unlikely((opt_retries >= 0) && (++failures > opt_retries))) { |
|
|
|
applog(LOG_ERR, "...terminating workio thread"); |
|
|
|
applog(LOG_ERR, "...terminating workio thread"); |
|
|
|
return false; |
|
|
|
exit (1); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* pause, then restart work-request loop */ |
|
|
|
/* pause, then restart work-request loop */ |
|
|
@ -458,21 +471,43 @@ static bool workio_submit_work(struct workio_cmd *wc, CURL *curl) |
|
|
|
sleep(opt_fail_pause); |
|
|
|
sleep(opt_fail_pause); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
free(hexstr); |
|
|
|
|
|
|
|
out: |
|
|
|
|
|
|
|
curl_easy_cleanup(curl); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Work is submitted asynchronously by creating a thread for each submit
|
|
|
|
|
|
|
|
* thus avoiding the mining threads having to wait till work is submitted |
|
|
|
|
|
|
|
* before they can continue working. */ |
|
|
|
|
|
|
|
static bool workio_submit_work(struct workio_cmd *wc) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
struct work *work; |
|
|
|
|
|
|
|
pthread_t thr; |
|
|
|
|
|
|
|
char *hexstr; |
|
|
|
|
|
|
|
pid_t child; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
work = wc->u.work; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* build hex string */ |
|
|
|
|
|
|
|
hexstr = bin2hex(work->data, sizeof(work->data)); |
|
|
|
|
|
|
|
if (unlikely(!hexstr)) { |
|
|
|
|
|
|
|
applog(LOG_ERR, "workio_submit_work OOM"); |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (pthread_create(&thr, NULL, submit_thread, (void *)hexstr)) { |
|
|
|
|
|
|
|
applog(LOG_ERR, "Failed to create submit_thread"); |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void *workio_thread(void *userdata) |
|
|
|
static void *workio_thread(void *userdata) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct thr_info *mythr = userdata; |
|
|
|
struct thr_info *mythr = userdata; |
|
|
|
CURL *curl; |
|
|
|
|
|
|
|
bool ok = true; |
|
|
|
bool ok = true; |
|
|
|
|
|
|
|
|
|
|
|
curl = curl_easy_init(); |
|
|
|
|
|
|
|
if (unlikely(!curl)) { |
|
|
|
|
|
|
|
applog(LOG_ERR, "CURL initialization failed"); |
|
|
|
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (ok) { |
|
|
|
while (ok) { |
|
|
|
struct workio_cmd *wc; |
|
|
|
struct workio_cmd *wc; |
|
|
|
|
|
|
|
|
|
|
@ -486,10 +521,10 @@ static void *workio_thread(void *userdata) |
|
|
|
/* process workio_cmd */ |
|
|
|
/* process workio_cmd */ |
|
|
|
switch (wc->cmd) { |
|
|
|
switch (wc->cmd) { |
|
|
|
case WC_GET_WORK: |
|
|
|
case WC_GET_WORK: |
|
|
|
ok = workio_get_work(wc, curl); |
|
|
|
ok = workio_get_work(wc); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case WC_SUBMIT_WORK: |
|
|
|
case WC_SUBMIT_WORK: |
|
|
|
ok = workio_submit_work(wc, curl); |
|
|
|
ok = workio_submit_work(wc); |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
default: /* should never happen */ |
|
|
|
default: /* should never happen */ |
|
|
@ -501,7 +536,6 @@ static void *workio_thread(void *userdata) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
tq_freeze(mythr->q); |
|
|
|
tq_freeze(mythr->q); |
|
|
|
curl_easy_cleanup(curl); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return NULL; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
} |
|
|
|