|
@@ -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;
|
|
|
}
|
|
}
|