mirror of
https://github.com/GOSTSec/ccminer
synced 2025-02-03 10:24:24 +00:00
8cf21599d4
Todo: - send block height via stratum protocol (encoded in jobid?) - remove equi/blake2 cpu algorithm to use common one the extranonce imcompatibility is related to the solver nonce data, offsets may be reversed in nheqminer, to check... The solver was adapted for SM 3.0+ support (no perf changes) Note: The solver was not improved on purpose, to be able compare the two miners performances (nheqminer 0.5c the last open sourced, and ccminer) Signed-off-by: Tanguy Pruvot <tanguy.pruvot@gmail.com> stratum: code cleanup, move equi fns in equi folder
242 lines
7.4 KiB
C++
242 lines
7.4 KiB
C++
/**
|
|
* 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;
|
|
}
|
|
|
|
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;
|
|
}
|