GOSTcoin support for ccminer CUDA miner project, compatible with most nvidia cards
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

274 lines
8.1 KiB

/**
* Equihash specific stratum protocol
* tpruvot@github - 2017 - Part under GPLv3 Licence
*/
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <miner.h>
#include "equihash.h"
extern struct stratum_ctx stratum;
extern pthread_mutex_t stratum_work_lock;
// ZEC uses a different scale to compute diff...
// sample targets to diff (stored in the reverse byte order in work->target)
// 0007fff800000000000000000000000000000000000000000000000000000000 is stratum diff 32
// 003fffc000000000000000000000000000000000000000000000000000000000 is stratum diff 4
// 00ffff0000000000000000000000000000000000000000000000000000000000 is stratum diff 1
double target_to_diff_equi(uint32_t* target)
{
uchar* tgt = (uchar*) target;
uint64_t m =
(uint64_t)tgt[30] << 24 |
(uint64_t)tgt[29] << 16 |
(uint64_t)tgt[28] << 8 |
(uint64_t)tgt[27] << 0;
if (!m)
return 0.;
else
return (double)0xffff0000UL/m;
}
void diff_to_target_equi(uint32_t *target, double diff)
{
uint64_t m;
int k;
for (k = 6; k > 0 && diff > 1.0; k--)
diff /= 4294967296.0;
m = (uint64_t)(4294901760.0 / diff);
if (m == 0 && k == 6)
memset(target, 0xff, 32);
else {
memset(target, 0, 32);
target[k + 1] = (uint32_t)(m >> 8);
target[k + 2] = (uint32_t)(m >> 40);
//memset(target, 0xff, 6*sizeof(uint32_t));
for (k = 0; k < 28 && ((uint8_t*)target)[k] == 0; k++)
((uint8_t*)target)[k] = 0xff;
}
}
/* compute nbits to get the network diff */
double equi_network_diff(struct work *work)
{
//KMD bits: "1e 015971",
//KMD target: "00 00 015971000000000000000000000000000000000000000000000000000000",
//KMD bits: "1d 686aaf",
//KMD target: "00 0000 686aaf0000000000000000000000000000000000000000000000000000",
uint32_t nbits = work->data[26];
uint32_t bits = (nbits & 0xffffff);
int16_t shift = (swab32(nbits) & 0xff);
shift = (31 - shift) * 8; // 8 bits shift for 0x1e, 16 for 0x1d
uint64_t tgt64 = swab32(bits);
tgt64 = tgt64 << shift;
// applog_hex(&tgt64, 8);
uint8_t net_target[32] = { 0 };
for (int b=0; b<8; b++)
net_target[31-b] = ((uint8_t*)&tgt64)[b];
// applog_hex(net_target, 32);
double d = target_to_diff_equi((uint32_t*)net_target);
return d;
}
void equi_work_set_target(struct work* work, double diff)
{
// target is given as data by the equihash stratum
// memcpy(work->target, stratum.job.claim, 32); // claim field is only used for lbry
diff_to_target_equi(work->target, diff);
//applog(LOG_BLUE, "diff %f to target :", diff);
//applog_hex(work->target, 32);
work->targetdiff = diff;
}
bool equi_stratum_set_target(struct stratum_ctx *sctx, json_t *params)
{
uint8_t target_bin[32], target_be[32];
const char *target_hex = json_string_value(json_array_get(params, 0));
if (!target_hex || strlen(target_hex) == 0)
return false;
hex2bin(target_bin, target_hex, 32);
memset(target_be, 0xff, 32);
int filled = 0;
for (int i=0; i<32; i++) {
if (filled == 3) break;
target_be[31-i] = target_bin[i];
if (target_bin[i]) filled++;
}
memcpy(sctx->job.claim, target_be, 32); // hack, unused struct field
pthread_mutex_lock(&stratum_work_lock);
sctx->next_diff = target_to_diff_equi((uint32_t*) &target_be);
pthread_mutex_unlock(&stratum_work_lock);
//applog(LOG_BLUE, "low diff %f", sctx->next_diff);
//applog_hex(target_be, 32);
return true;
}
bool equi_stratum_notify(struct stratum_ctx *sctx, json_t *params)
{
const char *job_id, *version, *prevhash, *coinb1, *coinb2, *nbits, *stime;
size_t coinb1_size, coinb2_size;
bool clean, ret = false;
int ntime, i, p=0;
job_id = json_string_value(json_array_get(params, p++));
version = json_string_value(json_array_get(params, p++));
prevhash = json_string_value(json_array_get(params, p++));
coinb1 = json_string_value(json_array_get(params, p++)); //merkle
coinb2 = json_string_value(json_array_get(params, p++)); //blank (reserved)
stime = json_string_value(json_array_get(params, p++));
nbits = json_string_value(json_array_get(params, p++));
clean = json_is_true(json_array_get(params, p)); p++;
if (!job_id || !prevhash || !coinb1 || !coinb2 || !version || !nbits || !stime ||
strlen(prevhash) != 64 || strlen(version) != 8 ||
strlen(coinb1) != 64 || strlen(coinb2) != 64 ||
strlen(nbits) != 8 || strlen(stime) != 8) {
applog(LOG_ERR, "Stratum notify: invalid parameters");
goto out;
}
/* store stratum server time diff */
hex2bin((uchar *)&ntime, stime, 4);
ntime = ntime - (int) time(0);
if (ntime > sctx->srvtime_diff) {
sctx->srvtime_diff = ntime;
if (opt_protocol && ntime > 20)
applog(LOG_DEBUG, "stratum time is at least %ds in the future", ntime);
}
pthread_mutex_lock(&stratum_work_lock);
hex2bin(sctx->job.version, version, 4);
hex2bin(sctx->job.prevhash, prevhash, 32);
coinb1_size = strlen(coinb1) / 2;
coinb2_size = strlen(coinb2) / 2;
sctx->job.coinbase_size = coinb1_size + coinb2_size + // merkle + reserved
sctx->xnonce1_size + sctx->xnonce2_size; // extranonce and...
sctx->job.coinbase = (uchar*) realloc(sctx->job.coinbase, sctx->job.coinbase_size);
hex2bin(sctx->job.coinbase, coinb1, coinb1_size);
hex2bin(sctx->job.coinbase + coinb1_size, coinb2, coinb2_size);
sctx->job.xnonce2 = sctx->job.coinbase + coinb1_size + coinb2_size + sctx->xnonce1_size;
if (!sctx->job.job_id || strcmp(sctx->job.job_id, job_id))
memset(sctx->job.xnonce2, 0, sctx->xnonce2_size);
memcpy(sctx->job.coinbase + coinb1_size + coinb2_size, sctx->xnonce1, sctx->xnonce1_size);
for (i = 0; i < sctx->job.merkle_count; i++)
free(sctx->job.merkle[i]);
free(sctx->job.merkle);
sctx->job.merkle = NULL;
sctx->job.merkle_count = 0;
free(sctx->job.job_id);
sctx->job.job_id = strdup(job_id);
hex2bin(sctx->job.nbits, nbits, 4);
hex2bin(sctx->job.ntime, stime, 4);
sctx->job.clean = clean;
sctx->job.diff = sctx->next_diff;
pthread_mutex_unlock(&stratum_work_lock);
ret = true;
out:
return ret;
}
// equihash stratum protocol is not standard, use client.show_message to pass block height
bool equi_stratum_show_message(struct stratum_ctx *sctx, json_t *id, json_t *params)
{
char *s;
json_t *val;
bool ret;
val = json_array_get(params, 0);
if (val) {
const char* data = json_string_value(val);
if (data && strlen(data)) {
char symbol[32] = { 0 };
int ss = sscanf(data, "equihash %s block %u", symbol, &sctx->job.height);
if (opt_debug && ss > 1) applog(LOG_DEBUG, "%s", data);
}
}
if (!id || json_is_null(id))
return true;
val = json_object();
json_object_set(val, "id", id);
json_object_set_new(val, "error", json_null());
json_object_set_new(val, "result", json_true());
s = json_dumps(val, 0);
ret = stratum_send_line(sctx, s);
json_decref(val);
free(s);
return ret;
}
void equi_store_work_solution(struct work* work, uint32_t* hash, void* sol_data)
{
int nonce = work->valid_nonces-1;
memcpy(work->extra, sol_data, 1347);
bn_store_hash_target_ratio(hash, work->target, work, nonce);
//work->sharediff[nonce] = target_to_diff_equi(hash);
}
#define JSON_SUBMIT_BUF_LEN (4*1024)
// called by submit_upstream_work()
bool equi_stratum_submit(struct pool_infos *pool, struct work *work)
{
char _ALIGN(64) s[JSON_SUBMIT_BUF_LEN];
char _ALIGN(64) timehex[16] = { 0 };
char *jobid, *noncestr, *solhex;
int idnonce = work->submit_nonce_id;
// scanned nonce
work->data[EQNONCE_OFFSET] = work->nonces[idnonce];
unsigned char * nonce = (unsigned char*) (&work->data[27]);
size_t nonce_len = 32 - stratum.xnonce1_size;
// long nonce without pool prefix (extranonce)
noncestr = bin2hex(&nonce[stratum.xnonce1_size], nonce_len);
solhex = (char*) calloc(1, 1344*2 + 64);
if (!solhex || !noncestr) {
applog(LOG_ERR, "unable to alloc share memory");
return false;
}
cbin2hex(solhex, (const char*) work->extra, 1347);
jobid = work->job_id + 8;
sprintf(timehex, "%08x", swab32(work->data[25]));
snprintf(s, sizeof(s), "{\"method\":\"mining.submit\",\"params\":"
"[\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"], \"id\":%u}",
pool->user, jobid, timehex, noncestr, solhex,
stratum.job.shares_count + 10);
free(solhex);
free(noncestr);
gettimeofday(&stratum.tv_submit, NULL);
if(!stratum_send_line(&stratum, s)) {
applog(LOG_ERR, "%s stratum_send_line failed", __func__);
return false;
}
stratum.sharediff = work->sharediff[idnonce];
stratum.job.shares_count++;
return true;
}