made local mining work with segwit, restored scrypt stuff
This commit is contained in:
parent
a4bb8de94a
commit
897f30df0f
2 changed files with 156 additions and 43 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -26,3 +26,7 @@ config.sub
|
|||
|
||||
mingw32-config.cache
|
||||
|
||||
|
||||
.idea/
|
||||
|
||||
compile_commands.json
|
||||
|
|
167
cpu-miner.c
167
cpu-miner.c
|
@ -102,10 +102,14 @@ struct workio_cmd {
|
|||
|
||||
enum algos {
|
||||
ALGO_LBRY, /* lbry */
|
||||
ALGO_SCRYPT, /* scrypt(1024,1,1) */
|
||||
ALGO_SHA256D, /* SHA-256d */
|
||||
};
|
||||
|
||||
static const char *algo_names[] = {
|
||||
[ALGO_LBRY] = "lbry",
|
||||
[ALGO_SCRYPT] = "scrypt",
|
||||
[ALGO_SHA256D] = "sha256d",
|
||||
};
|
||||
|
||||
bool opt_debug = false;
|
||||
|
@ -118,6 +122,7 @@ bool have_gbt = true;
|
|||
bool allow_getwork = false;
|
||||
bool want_stratum = false;
|
||||
bool have_stratum = false;
|
||||
bool want_segwit = false;
|
||||
bool use_syslog = false;
|
||||
static bool opt_background = false;
|
||||
static bool opt_quiet = false;
|
||||
|
@ -168,7 +173,7 @@ Usage: " PROGRAM_NAME " [OPTIONS]\n\
|
|||
Options:\n\
|
||||
-a, --algo=ALGO specify the algorithm to use\n\
|
||||
lbry (default)\n\
|
||||
scrypt scrypt(1024, 1, 1) (default)\n\
|
||||
scrypt scrypt(1024, 1, 1)\n\
|
||||
scrypt:N scrypt(N, 1, 1)\n\
|
||||
sha256d SHA-256d\n\
|
||||
-o, --url=URL URL of mining server\n\
|
||||
|
@ -187,11 +192,14 @@ Options:\n\
|
|||
--coinbase-addr=ADDR payout address for solo mining\n\
|
||||
--coinbase-sig=TEXT data to insert in the coinbase when possible\n\
|
||||
--no-longpoll disable long polling support\n\
|
||||
--getwork enable getwork support\n\
|
||||
--no-gbt disable getblocktemplate support\n\
|
||||
--stratum enable X-Stratum support\n\
|
||||
--no-redirect ignore requests to change the URL of the mining server\n\
|
||||
-q, --quiet disable per-thread hashmeter output\n\
|
||||
-D, --debug enable debug output\n\
|
||||
-P, --protocol-dump verbose dump of protocol-level activities\n"
|
||||
-P, --protocol-dump verbose dump of protocol-level activities\n\
|
||||
--segwit include Segwit transactions in the mined data\n"
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
"\
|
||||
-S, --syslog use system log for output messages\n"
|
||||
|
@ -229,8 +237,10 @@ static struct option const options[] = {
|
|||
{ "debug", 0, NULL, 'D' },
|
||||
{ "help", 0, NULL, 'h' },
|
||||
{ "no-gbt", 0, NULL, 1011 },
|
||||
{ "getwork", 0, NULL, 1010 },
|
||||
{ "no-longpoll", 0, NULL, 1003 },
|
||||
{ "no-redirect", 0, NULL, 1009 },
|
||||
{ "stratum", 0, NULL, 1007 },
|
||||
{ "pass", 1, NULL, 'p' },
|
||||
{ "protocol-dump", 0, NULL, 'P' },
|
||||
{ "proxy", 1, NULL, 'x' },
|
||||
|
@ -238,6 +248,7 @@ static struct option const options[] = {
|
|||
{ "retries", 1, NULL, 'r' },
|
||||
{ "retry-pause", 1, NULL, 'R' },
|
||||
{ "scantime", 1, NULL, 's' },
|
||||
{ "segwit", 0, NULL, 1016 },
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
{ "syslog", 0, NULL, 'S' },
|
||||
#endif
|
||||
|
@ -314,6 +325,30 @@ static bool jobj_binary(const json_t *obj, const char *key,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool work_decode(const json_t *val, struct work *work)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (unlikely(!jobj_binary(val, "data", work->data, sizeof(work->data)))) {
|
||||
applog(LOG_ERR, "JSON invalid data");
|
||||
goto err_out;
|
||||
}
|
||||
if (unlikely(!jobj_binary(val, "target", work->target, sizeof(work->target)))) {
|
||||
applog(LOG_ERR, "JSON invalid target");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(work->data); i++)
|
||||
work->data[i] = le32dec(work->data + i);
|
||||
for (i = 0; i < ARRAY_SIZE(work->target); i++)
|
||||
work->target[i] = le32dec(work->target + i);
|
||||
|
||||
return true;
|
||||
|
||||
err_out:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool gbt_work_decode(const json_t *val, struct work *work)
|
||||
{
|
||||
int i, n;
|
||||
|
@ -322,7 +357,7 @@ static bool gbt_work_decode(const json_t *val, struct work *work)
|
|||
uint32_t target[8];
|
||||
uint32_t claimtrie[8];
|
||||
int cbtx_size;
|
||||
unsigned char *cbtx = NULL;
|
||||
unsigned char *cbtx = NULL, *cbtx_txid = NULL;
|
||||
unsigned char *tx = NULL;
|
||||
int tx_count, tx_size;
|
||||
unsigned char txc_vi[9];
|
||||
|
@ -373,7 +408,7 @@ static bool gbt_work_decode(const json_t *val, struct work *work)
|
|||
}
|
||||
version = json_integer_value(tmp);
|
||||
|
||||
if (unlikely(!jobj_binary(val, "claimtrie", claimtrie, sizeof(claimtrie)))) {
|
||||
if (opt_algo == ALGO_LBRY && unlikely(!jobj_binary(val, "claimtrie", claimtrie, sizeof(claimtrie)))) {
|
||||
applog(LOG_ERR, "JSON invalid claimtrie");
|
||||
goto out;
|
||||
}
|
||||
|
@ -424,6 +459,23 @@ static bool gbt_work_decode(const json_t *val, struct work *work)
|
|||
applog(LOG_ERR, "JSON invalid coinbasetxn");
|
||||
goto out;
|
||||
}
|
||||
bool hasWitness = *(uint16_t*)(cbtx + 4) == 256;
|
||||
if (hasWitness && coinbase_append) {
|
||||
// TODO: make this work by using index 43 instead of 41 in the coinbase_append handler below
|
||||
// and then would we pass it in as one of our supported capabilities? Sure.
|
||||
applog(LOG_ERR, "This tool cannot append onto segwit transactions");
|
||||
goto out;
|
||||
}
|
||||
if (hasWitness) {
|
||||
cbtx_hex = json_string_value(json_object_get(tmp, "txid"));
|
||||
size_t txid_size = strlen(cbtx_hex) / 2;
|
||||
cbtx_txid = malloc(txid_size + 1);
|
||||
if (txid_size != 32 || !hex2bin(cbtx_txid, cbtx_hex, txid_size)) {
|
||||
applog(LOG_ERR, "Invalid txid on coinbase");
|
||||
goto out;
|
||||
}
|
||||
memrev(cbtx_txid, 32);
|
||||
}
|
||||
} else {
|
||||
int64_t cbvalue;
|
||||
if (!pk_script_size) {
|
||||
|
@ -563,6 +615,9 @@ static bool gbt_work_decode(const json_t *val, struct work *work)
|
|||
merkle_tree = malloc(32 * ((1 + tx_count + 1) & ~1));
|
||||
size_t tx_buf_size = 32 * 1024;
|
||||
tx = malloc(tx_buf_size);
|
||||
if (cbtx_txid)
|
||||
memcpy(merkle_tree[0], cbtx_txid, 32);
|
||||
else
|
||||
sha256d(merkle_tree[0], cbtx, cbtx_size);
|
||||
for (i = 0; i < tx_count; i++) {
|
||||
tmp = json_array_get(txa, i);
|
||||
|
@ -606,18 +661,22 @@ static bool gbt_work_decode(const json_t *val, struct work *work)
|
|||
}
|
||||
|
||||
/* assemble block header */
|
||||
memset(work->data, 0x00, sizeof(work->data));
|
||||
work->data[0] = swab32(version);
|
||||
for (i = 0; i < 8; i++)
|
||||
work->data[8 - i] = le32dec(prevhash + i);
|
||||
for (i = 0; i < 8; i++)
|
||||
work->data[9 + i] = be32dec((uint32_t *)merkle_tree[0] + i);
|
||||
int offset = 0;
|
||||
if (opt_algo == ALGO_LBRY) {
|
||||
for (i = 0; i < 8; i++)
|
||||
work->data[24 - i] = le32dec(claimtrie + i);
|
||||
work->data[25] = swab32(curtime);
|
||||
work->data[26] = le32dec(&bits);
|
||||
work->data[28] = 0x80000000;
|
||||
work->data[39] = 0x00000280;
|
||||
offset = 8;
|
||||
}
|
||||
work->data[17 + offset] = swab32(curtime);
|
||||
work->data[18 + offset] = le32dec(&bits);
|
||||
memset(work->data + 19 + offset, 0x00, 52);
|
||||
work->data[20 + offset] = 0x80000000;
|
||||
work->data[31 + offset] = 0x00000280;
|
||||
|
||||
if (unlikely(!jobj_binary(val, "target", target, sizeof(target)))) {
|
||||
applog(LOG_ERR, "JSON invalid target");
|
||||
|
@ -654,13 +713,14 @@ static bool gbt_work_decode(const json_t *val, struct work *work)
|
|||
out:
|
||||
free(tx);
|
||||
free(cbtx);
|
||||
free(cbtx_txid);
|
||||
free(merkle_tree);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void share_result(int result, const char *reason)
|
||||
{
|
||||
char s[345];
|
||||
char s[370];
|
||||
double hashrate;
|
||||
int i;
|
||||
|
||||
|
@ -687,7 +747,7 @@ static bool submit_upstream_work(CURL *curl, struct work *work)
|
|||
{
|
||||
json_t *val, *res, *reason;
|
||||
char data_str[2 * sizeof(work->data) + 1];
|
||||
char s[345];
|
||||
char s[370];
|
||||
int i;
|
||||
bool rc = false;
|
||||
|
||||
|
@ -724,20 +784,21 @@ static bool submit_upstream_work(CURL *curl, struct work *work)
|
|||
|
||||
for (i = 0; i < ARRAY_SIZE(work->data); i++)
|
||||
be32enc(work->data + i, work->data[i]);
|
||||
bin2hex(data_str, (unsigned char *)work->data, 112);
|
||||
int offset = opt_algo == ALGO_LBRY ? 112 : 80;
|
||||
bin2hex(data_str, (unsigned char *)work->data, offset);
|
||||
if (work->workid) {
|
||||
char *params;
|
||||
val = json_object();
|
||||
json_object_set_new(val, "workid", json_string(work->workid));
|
||||
params = json_dumps(val, 0);
|
||||
json_decref(val);
|
||||
req = malloc(160 + 2*112 + strlen(work->txs) + strlen(params));
|
||||
req = malloc(160 + 2*offset + strlen(work->txs) + strlen(params));
|
||||
sprintf(req,
|
||||
"{\"method\": \"submitblock\", \"params\": [\"%s%s\", %s], \"id\":1}\r\n",
|
||||
data_str, work->txs, params);
|
||||
free(params);
|
||||
} else {
|
||||
req = malloc(160 + 2*112 + strlen(work->txs));
|
||||
req = malloc(160 + 2*offset + strlen(work->txs));
|
||||
sprintf(req,
|
||||
"{\"method\": \"submitblock\", \"params\": [\"%s%s\"], \"id\":1}\r\n",
|
||||
data_str, work->txs);
|
||||
|
@ -803,14 +864,15 @@ static const char *getwork_req =
|
|||
"{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n";
|
||||
|
||||
#define GBT_CAPABILITIES "[\"coinbasetxn\", \"coinbasevalue\", \"longpoll\", \"workid\"]"
|
||||
#define GBT_RULES "[\"segwit\"]"
|
||||
#define GBT_NO_RULES "[]"
|
||||
|
||||
static const char *gbt_req =
|
||||
"{\"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": "
|
||||
GBT_CAPABILITIES "}], \"id\":0}\r\n";
|
||||
|
||||
GBT_CAPABILITIES ", \"rules\": " GBT_NO_RULES "}], \"id\":0}\r\n";
|
||||
static const char *gbt_lp_req =
|
||||
"{\"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": "
|
||||
GBT_CAPABILITIES "}], \"id\":0}\r\n";
|
||||
GBT_CAPABILITIES ", \"rules\": %s, \"longpollid\": \"%s\"}], \"id\":0}\r\n";
|
||||
|
||||
static bool get_upstream_work(CURL *curl, struct work *work)
|
||||
{
|
||||
|
@ -848,11 +910,14 @@ start:
|
|||
if (!val)
|
||||
return false;
|
||||
|
||||
if (have_gbt) {
|
||||
rc = gbt_work_decode(json_object_get(val, "result"), work);
|
||||
if (!rc) {
|
||||
if (!have_gbt) {
|
||||
json_decref(val);
|
||||
goto start;
|
||||
}
|
||||
} else
|
||||
rc = work_decode(json_object_get(val, "result"), work);
|
||||
|
||||
if (opt_debug && rc) {
|
||||
timeval_subtract(&diff, &tv_end, &tv_start);
|
||||
|
@ -1091,9 +1156,15 @@ static void stratum_gen_work(struct stratum_ctx *sctx, struct work *work)
|
|||
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);
|
||||
}
|
||||
|
||||
extern int scanhash_lbry(int thr_id, uint32_t *pdata, const uint32_t *ptarget,
|
||||
uint32_t max_nonce, uint64_t *hashes_done);
|
||||
|
||||
static void *miner_thread(void *userdata)
|
||||
{
|
||||
struct thr_info *mythr = userdata;
|
||||
|
@ -1122,6 +1193,17 @@ static void *miner_thread(void *userdata)
|
|||
affine_to_cpu(thr_id, thr_id % num_processors);
|
||||
}
|
||||
|
||||
if (opt_algo == ALGO_SCRYPT) {
|
||||
scratchbuf = scrypt_buffer_alloc(opt_scrypt_n);
|
||||
if (!scratchbuf) {
|
||||
applog(LOG_ERR, "scrypt buffer allocation failed");
|
||||
pthread_mutex_lock(&applog_lock);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int offset = opt_algo == ALGO_LBRY ? 8 : 0;
|
||||
|
||||
while (1) {
|
||||
unsigned long hashes_done;
|
||||
struct timeval tv_start, tv_end, diff;
|
||||
|
@ -1132,7 +1214,7 @@ static void *miner_thread(void *userdata)
|
|||
while (time(NULL) >= g_work_time + 120)
|
||||
sleep(1);
|
||||
pthread_mutex_lock(&g_work_lock);
|
||||
if (work.data[19] >= end_nonce && !memcmp(work.data, g_work.data, 76))
|
||||
if (work.data[19 + offset] >= end_nonce && !memcmp(work.data, g_work.data, 76 + offset * 4))
|
||||
stratum_gen_work(&stratum, &g_work);
|
||||
} else {
|
||||
int min_scantime = have_longpoll ? LP_SCANTIME : opt_scantime;
|
||||
|
@ -1140,7 +1222,7 @@ static void *miner_thread(void *userdata)
|
|||
pthread_mutex_lock(&g_work_lock);
|
||||
if (!have_stratum &&
|
||||
(time(NULL) - g_work_time >= min_scantime ||
|
||||
work.data[27] >= end_nonce)) {
|
||||
work.data[19 + offset] >= end_nonce)) {
|
||||
work_free(&g_work);
|
||||
if (unlikely(!get_work(mythr, &g_work))) {
|
||||
applog(LOG_ERR, "work retrieval failed, exiting "
|
||||
|
@ -1155,13 +1237,12 @@ static void *miner_thread(void *userdata)
|
|||
continue;
|
||||
}
|
||||
}
|
||||
/* if (memcmp(work.data, g_work.data, 76)) { */
|
||||
if (memcmp(work.data, g_work.data, 108)) {
|
||||
if (memcmp(work.data, g_work.data, 76 + offset * 4)) {
|
||||
work_free(&work);
|
||||
work_copy(&work, &g_work);
|
||||
work.data[27] = 0xffffffffU / opt_n_threads * thr_id;
|
||||
work.data[19 + offset] = 0xffffffffU / opt_n_threads * thr_id;
|
||||
} else
|
||||
work.data[27]++;
|
||||
work.data[19 + offset]++;
|
||||
pthread_mutex_unlock(&g_work_lock);
|
||||
work_restart[thr_id].restart = 0;
|
||||
|
||||
|
@ -1177,6 +1258,12 @@ static void *miner_thread(void *userdata)
|
|||
case ALGO_LBRY:
|
||||
max64 = 0x1fffff;
|
||||
break;
|
||||
case ALGO_SCRYPT:
|
||||
max64 = opt_scrypt_n < 16 ? 0x3ffff : 0x3fffff / opt_scrypt_n;
|
||||
break;
|
||||
case ALGO_SHA256D:
|
||||
max64 = 0x1fffff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (work.data[19] + max64 > end_nonce)
|
||||
|
@ -1193,7 +1280,15 @@ static void *miner_thread(void *userdata)
|
|||
rc = scanhash_lbry(thr_id, work.data, work.target,
|
||||
max_nonce, &hashes_done);
|
||||
break;
|
||||
case ALGO_SCRYPT:
|
||||
rc = scanhash_scrypt(thr_id, work.data, scratchbuf, work.target,
|
||||
max_nonce, &hashes_done, opt_scrypt_n);
|
||||
break;
|
||||
|
||||
case ALGO_SHA256D:
|
||||
rc = scanhash_sha256d(thr_id, work.data, work.target,
|
||||
max_nonce, &hashes_done);
|
||||
break;
|
||||
default:
|
||||
/* should never happen */
|
||||
goto out;
|
||||
|
@ -1288,8 +1383,8 @@ start:
|
|||
int err;
|
||||
|
||||
if (have_gbt) {
|
||||
req = malloc(strlen(gbt_lp_req) + strlen(lp_id) + 1);
|
||||
sprintf(req, gbt_lp_req, lp_id);
|
||||
req = malloc(strlen(gbt_lp_req) + strlen(lp_id) + 1 + strlen(GBT_RULES));
|
||||
sprintf(req, gbt_lp_req, want_segwit ? GBT_RULES : GBT_NO_RULES, lp_id);
|
||||
}
|
||||
val = json_rpc_call(curl, lp_url, rpc_userpass,
|
||||
req ? req : getwork_req, &err,
|
||||
|
@ -1302,13 +1397,15 @@ start:
|
|||
}
|
||||
if (likely(val)) {
|
||||
bool rc;
|
||||
//applog(LOG_INFO, "LONGPOLL pushed new work");
|
||||
res = json_object_get(val, "result");
|
||||
soval = json_object_get(res, "submitold");
|
||||
submit_old = soval ? json_is_true(soval) : false;
|
||||
pthread_mutex_lock(&g_work_lock);
|
||||
work_free(&g_work);
|
||||
if (have_gbt)
|
||||
rc = gbt_work_decode(res, &g_work);
|
||||
else
|
||||
rc = work_decode(res, &g_work);
|
||||
if (rc) {
|
||||
time(&g_work_time);
|
||||
restart_threads();
|
||||
|
@ -1521,6 +1618,15 @@ static void parse_arg(int key, char *arg, char *pname)
|
|||
opt_algo = i;
|
||||
break;
|
||||
}
|
||||
if (arg[v] == ':' && i == ALGO_SCRYPT) {
|
||||
char *ep;
|
||||
v = strtol(arg+v+1, &ep, 10);
|
||||
if (*ep || v & (v-1) || v < 2)
|
||||
continue;
|
||||
opt_algo = i;
|
||||
opt_scrypt_n = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i == ARRAY_SIZE(algo_names)) {
|
||||
|
@ -1694,13 +1800,13 @@ static void parse_arg(int key, char *arg, char *pname)
|
|||
want_longpoll = false;
|
||||
break;
|
||||
case 1007:
|
||||
want_stratum = false;
|
||||
want_stratum = true;
|
||||
break;
|
||||
case 1009:
|
||||
opt_redirect = false;
|
||||
break;
|
||||
case 1010:
|
||||
allow_getwork = false;
|
||||
allow_getwork = true;
|
||||
break;
|
||||
case 1011:
|
||||
have_gbt = false;
|
||||
|
@ -1720,6 +1826,9 @@ static void parse_arg(int key, char *arg, char *pname)
|
|||
}
|
||||
strcpy(coinbase_sig, arg);
|
||||
break;
|
||||
case 1016:
|
||||
want_segwit = true;
|
||||
break;
|
||||
case 'S':
|
||||
use_syslog = true;
|
||||
break;
|
||||
|
|
Loading…
Reference in a new issue