Skip to content

Commit

Permalink
Merge pull request lucasjones#6 from LucasJones/dev
Browse files Browse the repository at this point in the history
JSON-RPC 2 tcp support
  • Loading branch information
lucasjones committed May 24, 2014
2 parents afc2d00 + 67ee0db commit 1070438
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 108 deletions.
215 changes: 130 additions & 85 deletions cpu-miner.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ static bool opt_background = false;
static bool opt_quiet = false;
static int opt_retries = -1;
static int opt_fail_pause = 10;
static int jsonrpc_2 = false;
bool jsonrpc_2 = false;
int opt_timeout = 0;
static int opt_scantime = 5;
static json_t *opt_config;
Expand Down Expand Up @@ -274,15 +274,6 @@ static struct option const options[] = {
{ 0, 0, 0, 0 }
};

struct work {
uint32_t data[32];
uint32_t target[8];

char *job_id;
size_t xnonce2_len;
unsigned char *xnonce2;
};

static struct work g_work;
static time_t g_work_time;
static pthread_mutex_t g_work_lock;
Expand Down Expand Up @@ -386,7 +377,7 @@ static bool jobj_binary(const json_t *obj, const char *key, void *buf,
return true;
}

static bool rpc2_job_decode(const json_t *job, struct work *work) {
bool rpc2_job_decode(const json_t *job, struct work *work) {
if (!jsonrpc_2) {
applog(LOG_ERR, "Tried to decode job without JSON-RPC 2.0");
return false;
Expand Down Expand Up @@ -414,6 +405,7 @@ static bool rpc2_job_decode(const json_t *job, struct work *work) {
char *blob = malloc(blobLen / 2);
if (!hex2bin(blob, hexblob, blobLen / 2)) {
applog(LOG_ERR, "JSON inval blob");
pthread_mutex_unlock(&rpc2_job_lock);
goto err_out;
}
if (rpc2_blob) {
Expand All @@ -434,7 +426,7 @@ static bool rpc2_job_decode(const json_t *job, struct work *work) {
hashrate += thr_hashrates[i];
pthread_mutex_unlock(&stats_lock);
double difficulty = (((double) 0xffffffff) / target);
applog(LOG_INFO, "[JSON-RPC] diff set to %g", difficulty);
applog(LOG_INFO, "Pool set diff to %g", difficulty);
rpc2_target = target;
}

Expand All @@ -459,7 +451,6 @@ static bool rpc2_job_decode(const json_t *job, struct work *work) {
return true;

err_out:
pthread_mutex_unlock(&rpc2_job_lock);
return false;
}

Expand Down Expand Up @@ -489,7 +480,7 @@ static bool work_decode(const json_t *val, struct work *work) {
err_out: return false;
}

static bool login_decode(const json_t *val) {
bool rpc2_login_decode(const json_t *val) {
const char *id;
const char *s;

Expand Down Expand Up @@ -531,12 +522,6 @@ static bool login_decode(const json_t *val) {
return false;
}

json_t *job = json_object_get(res, "job");

if(!rpc2_job_decode(job, &g_work)) {
return false;
}

return true;

err_out: return false;
Expand Down Expand Up @@ -593,17 +578,32 @@ static bool submit_upstream_work(CURL *curl, struct work *work) {
uint32_t ntime, nonce;
char *ntimestr, *noncestr, *xnonce2str;

le32enc(&ntime, work->data[17]);
le32enc(&nonce, work->data[19]);
ntimestr = bin2hex((const unsigned char *) (&ntime), 4);
noncestr = bin2hex((const unsigned char *) (&nonce), 4);
xnonce2str = bin2hex(work->xnonce2, work->xnonce2_len);
snprintf(s, JSON_BUF_LEN,
"{\"method\": \"mining.submit\", \"params\": [\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"], \"id\":4}",
rpc_user, work->job_id, xnonce2str, ntimestr, noncestr);
free(ntimestr);
if (jsonrpc_2) {
noncestr = bin2hex(((const unsigned char*)work->data) + 39, 4);
char hash[32];
switch(opt_algo) {
case ALGO_CRYPTONIGHT:
default:
cryptonight_hash(hash, work->data, 76);
}
char *hashhex = bin2hex(hash, 32);
snprintf(s, JSON_BUF_LEN,
"{\"method\": \"submit\", \"params\": {\"id\": \"%s\", \"job_id\": \"%s\", \"nonce\": \"%s\", \"result\": \"%s\"}, \"id\":1}\r\n",
rpc2_id, work->job_id, noncestr, hashhex);
free(hashhex);
} else {
le32enc(&ntime, work->data[17]);
le32enc(&nonce, work->data[19]);
ntimestr = bin2hex((const unsigned char *) (&ntime), 4);
noncestr = bin2hex((const unsigned char *) (&nonce), 4);
xnonce2str = bin2hex(work->xnonce2, work->xnonce2_len);
snprintf(s, JSON_BUF_LEN,
"{\"method\": \"mining.submit\", \"params\": [\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"], \"id\":4}",
rpc_user, work->job_id, xnonce2str, ntimestr, noncestr);
free(ntimestr);
free(xnonce2str);
}
free(noncestr);
free(xnonce2str);

if (unlikely(!stratum_send_line(&stratum, s))) {
applog(LOG_ERR, "submit_upstream_work stratum_send_line failed");
Expand Down Expand Up @@ -732,7 +732,17 @@ static bool rpc2_login(CURL *curl) {

// applog(LOG_DEBUG, "JSON value: %s", json_dumps(val, 0));

rc = login_decode(val);
rc = rpc2_login_decode(val);

json_t *result = json_object_get(val, "result");

if(!result) goto end;

json_t *job = json_object_get(result, "job");

if(!rpc2_job_decode(job, &g_work)) {
goto end;
}

if (opt_debug && rc) {
timeval_subtract(&diff, &tv_end, &tv_start);
Expand Down Expand Up @@ -844,7 +854,7 @@ static void *workio_thread(void *userdata) {
return NULL ;
}

if(jsonrpc_2) {
if(!have_stratum) {
ok = workio_login(curl);
}

Expand Down Expand Up @@ -953,48 +963,55 @@ static void stratum_gen_work(struct stratum_ctx *sctx, struct work *work) {

pthread_mutex_lock(&sctx->work_lock);

free(work->job_id);
work->job_id = strdup(sctx->job.job_id);
work->xnonce2_len = sctx->xnonce2_size;
work->xnonce2 = realloc(work->xnonce2, sctx->xnonce2_size);
memcpy(work->xnonce2, sctx->job.xnonce2, sctx->xnonce2_size);

/* Generate merkle root */
sha256d(merkle_root, sctx->job.coinbase, sctx->job.coinbase_size);
for (i = 0; i < sctx->job.merkle_count; i++) {
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++)
;

/* Assemble block header */
memset(work->data, 0, 128);
work->data[0] = le32dec(sctx->job.version);
for (i = 0; i < 8; i++)
work->data[1 + i] = le32dec((uint32_t *) sctx->job.prevhash + i);
for (i = 0; i < 8; i++)
work->data[9 + i] = be32dec((uint32_t *) merkle_root + i);
work->data[17] = le32dec(sctx->job.ntime);
work->data[18] = le32dec(sctx->job.nbits);
work->data[20] = 0x80000000;
work->data[31] = 0x00000280;

pthread_mutex_unlock(&sctx->work_lock);

if (opt_debug) {
char *xnonce2str = bin2hex(work->xnonce2, work->xnonce2_len);
applog(LOG_DEBUG, "DEBUG: job_id='%s' extranonce2=%s ntime=%08x",
work->job_id, xnonce2str, swab32(work->data[17]));
free(xnonce2str);
}

if (opt_algo == ALGO_SCRYPT)
diff_to_target(work->target, sctx->job.diff / 65536.0);
else
diff_to_target(work->target, sctx->job.diff);
if (jsonrpc_2) {
free(work->job_id);
memcpy(work, &sctx->work, sizeof(struct work));
work->job_id = strdup(sctx->work.job_id);
pthread_mutex_unlock(&sctx->work_lock);
} else {
free(work->job_id);
work->job_id = strdup(sctx->job.job_id);
work->xnonce2_len = sctx->xnonce2_size;
work->xnonce2 = realloc(work->xnonce2, sctx->xnonce2_size);
memcpy(work->xnonce2, sctx->job.xnonce2, sctx->xnonce2_size);

/* Generate merkle root */
sha256d(merkle_root, sctx->job.coinbase, sctx->job.coinbase_size);
for (i = 0; i < sctx->job.merkle_count; i++) {
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++)
;

/* Assemble block header */
memset(work->data, 0, 128);
work->data[0] = le32dec(sctx->job.version);
for (i = 0; i < 8; i++)
work->data[1 + i] = le32dec((uint32_t *) sctx->job.prevhash + i);
for (i = 0; i < 8; i++)
work->data[9 + i] = be32dec((uint32_t *) merkle_root + i);
work->data[17] = le32dec(sctx->job.ntime);
work->data[18] = le32dec(sctx->job.nbits);
work->data[20] = 0x80000000;
work->data[31] = 0x00000280;

pthread_mutex_unlock(&sctx->work_lock);

if (opt_debug) {
char *xnonce2str = bin2hex(work->xnonce2, work->xnonce2_len);
applog(LOG_DEBUG, "DEBUG: job_id='%s' extranonce2=%s ntime=%08x",
work->job_id, xnonce2str, swab32(work->data[17]));
free(xnonce2str);
}

if (opt_algo == ALGO_SCRYPT)
diff_to_target(work->target, sctx->job.diff / 65536.0);
else
diff_to_target(work->target, sctx->job.diff);
}
}

static void *miner_thread(void *userdata) {
Expand Down Expand Up @@ -1040,7 +1057,8 @@ static void *miner_thread(void *userdata) {
sleep(1);
pthread_mutex_lock(&g_work_lock);
if ((*nonceptr) >= end_nonce
&& !(jsonrpc_2 ? memcmp(work.data, g_work.data, 39)
&& !(jsonrpc_2 ? memcmp(work.data, g_work.data, 39) ||
memcmp(((uint8_t*) work.data) + 43, ((uint8_t*) g_work.data) + 43, 33)
: memcmp(work.data, g_work.data, 76)))
stratum_gen_work(&stratum, &g_work);
} else {
Expand All @@ -1063,7 +1081,7 @@ static void *miner_thread(void *userdata) {
continue;
}
}
if (jsonrpc_2 ? memcmp(work.data, g_work.data, 39) : memcmp(work.data, g_work.data, 76)) {
if (jsonrpc_2 ? memcmp(work.data, g_work.data, 39) || memcmp(((uint8_t*) work.data) + 43, ((uint8_t*) g_work.data) + 43, 33) : memcmp(work.data, g_work.data, 76)) {
work_free(&work);
work_copy(&work, &g_work);
nonceptr = (uint32_t*) (((char*)work.data) + (jsonrpc_2 ? 39 : 76));
Expand Down Expand Up @@ -1321,6 +1339,7 @@ static bool stratum_handle_response(char *buf) {
json_t *val, *err_val, *res_val, *id_val;
json_error_t err;
bool ret = false;
bool valid = false;

val = JSON_LOADS(buf, &err);
if (!val) {
Expand All @@ -1335,8 +1354,20 @@ static bool stratum_handle_response(char *buf) {
if (!id_val || json_is_null(id_val) || !res_val)
goto out;

share_result(json_is_true(res_val), NULL,
err_val ? json_string_value(json_array_get(err_val, 1)) : NULL );
if(jsonrpc_2) {
json_t *status = json_object_get(res_val, "status");
if(status) {
const char *s = json_string_value(status);
valid = !strcmp(s, "OK") && json_is_null(err_val);
} else {
valid = json_is_null(err_val);
}
} else {
valid = json_is_true(res_val);
}

share_result(valid, NULL,
err_val ? (jsonrpc_2 ? json_string_value(err_val) : json_string_value(json_array_get(err_val, 1))) : NULL );

ret = true;
out: if (val)
Expand Down Expand Up @@ -1377,16 +1408,30 @@ static void *stratum_thread(void *userdata) {
}
}

if (stratum.job.job_id
&& (!g_work_time || strcmp(stratum.job.job_id, g_work.job_id))) {
pthread_mutex_lock(&g_work_lock);
stratum_gen_work(&stratum, &g_work);
time(&g_work_time);
pthread_mutex_unlock(&g_work_lock);
if (stratum.job.clean) {
if (jsonrpc_2) {
if (stratum.work.job_id
&& (!g_work_time
|| strcmp(stratum.work.job_id, g_work.job_id))) {
pthread_mutex_lock(&g_work_lock);
stratum_gen_work(&stratum, &g_work);
time(&g_work_time);
pthread_mutex_unlock(&g_work_lock);
applog(LOG_INFO, "Stratum detected new block");
restart_threads();
}
} else {
if (stratum.job.job_id
&& (!g_work_time
|| strcmp(stratum.job.job_id, g_work.job_id))) {
pthread_mutex_lock(&g_work_lock);
stratum_gen_work(&stratum, &g_work);
time(&g_work_time);
pthread_mutex_unlock(&g_work_lock);
if (stratum.job.clean) {
applog(LOG_INFO, "Stratum detected new block");
restart_threads();
}
}
}

if (!stratum_socket_full(&stratum, 120)) {
Expand Down
14 changes: 14 additions & 0 deletions miner.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ extern struct thr_info *thr_info;
extern int longpoll_thr_id;
extern int stratum_thr_id;
extern struct work_restart *work_restart;
extern bool jsonrpc_2;

#define JSON_RPC_LONGPOLL (1 << 0)
#define JSON_RPC_QUIET_404 (1 << 1)
Expand All @@ -229,6 +230,15 @@ extern int timeval_subtract(struct timeval *result, struct timeval *x,
extern bool fulltest(const uint32_t *hash, const uint32_t *target);
extern void diff_to_target(uint32_t *target, double diff);

struct work {
uint32_t data[32];
uint32_t target[8];

char *job_id;
size_t xnonce2_len;
unsigned char *xnonce2;
};

struct stratum_job {
char *job_id;
unsigned char prevhash[32];
Expand Down Expand Up @@ -262,6 +272,7 @@ struct stratum_ctx {
unsigned char *xnonce1;
size_t xnonce2_size;
struct stratum_job job;
struct work work;
pthread_mutex_t work_lock;
};

Expand All @@ -274,6 +285,9 @@ bool stratum_subscribe(struct stratum_ctx *sctx);
bool stratum_authorize(struct stratum_ctx *sctx, const char *user, const char *pass);
bool stratum_handle_method(struct stratum_ctx *sctx, const char *s);

extern bool rpc2_job_decode(const json_t *job, struct work *work);
extern bool rpc2_login_decode(const json_t *val);

struct thread_q;

extern struct thread_q *tq_new(void);
Expand Down
Loading

0 comments on commit 1070438

Please sign in to comment.