|
|
@ -142,10 +142,13 @@ static struct { |
|
|
|
double diff; |
|
|
|
double diff; |
|
|
|
|
|
|
|
|
|
|
|
char enonce1[32]; |
|
|
|
char enonce1[32]; |
|
|
|
|
|
|
|
uchar enonce1bin[16]; |
|
|
|
|
|
|
|
int enonce1constlen; |
|
|
|
|
|
|
|
|
|
|
|
int nonce2len; |
|
|
|
int nonce2len; |
|
|
|
int subnonce2len; |
|
|
|
int enonce2constlen; |
|
|
|
uint32_t subnonce2; |
|
|
|
uint32_t subnonce2; |
|
|
|
|
|
|
|
int enonce2varlen; |
|
|
|
} proxy_base; |
|
|
|
} proxy_base; |
|
|
|
|
|
|
|
|
|
|
|
static uint64_t workbase_id; |
|
|
|
static uint64_t workbase_id; |
|
|
@ -340,14 +343,60 @@ static void purge_share_hashtable(uint64_t wb_id) |
|
|
|
LOGINFO("Cleared %d shares from share hashtable", purged); |
|
|
|
LOGINFO("Cleared %d shares from share hashtable", purged); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void add_base(ckpool_t *ckp, workbase_t *wb, bool *new_block) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
workbase_t *tmp, *tmpa; |
|
|
|
|
|
|
|
int len, ret; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
wb->gentime = time(NULL); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
len = strlen(ckp->logdir) + 8 + 1 + 16; |
|
|
|
|
|
|
|
wb->logdir = ckalloc(len); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ck_wlock(&workbase_lock); |
|
|
|
|
|
|
|
wb->id = workbase_id++; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (strncmp(wb->prevhash, lasthash, 64)) { |
|
|
|
|
|
|
|
*new_block = true; |
|
|
|
|
|
|
|
memcpy(lasthash, wb->prevhash, 65); |
|
|
|
|
|
|
|
blockchange_id = wb->id; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (*new_block) { |
|
|
|
|
|
|
|
sprintf(wb->logdir, "%s%08x/", ckp->logdir, wb->height); |
|
|
|
|
|
|
|
ret = mkdir(wb->logdir, 0700); |
|
|
|
|
|
|
|
if (unlikely(ret && errno != EEXIST)) |
|
|
|
|
|
|
|
quit(1, "Failed to create log directory %s", wb->logdir); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
sprintf(wb->idstring, "%016lx", wb->id); |
|
|
|
|
|
|
|
/* Do not store the trailing slash for the subdir */ |
|
|
|
|
|
|
|
sprintf(wb->logdir, "%s%08x/%s", ckp->logdir, wb->height, wb->idstring); |
|
|
|
|
|
|
|
ret = mkdir(wb->logdir, 0700); |
|
|
|
|
|
|
|
if (unlikely(ret && errno != EEXIST)) |
|
|
|
|
|
|
|
quit(1, "Failed to create log directory %s", wb->logdir); |
|
|
|
|
|
|
|
HASH_ITER(hh, workbases, tmp, tmpa) { |
|
|
|
|
|
|
|
if (HASH_COUNT(workbases) < 3) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
/* Age old workbases older than 10 minutes old */ |
|
|
|
|
|
|
|
if (tmp->gentime < wb->gentime - 600) { |
|
|
|
|
|
|
|
HASH_DEL(workbases, tmp); |
|
|
|
|
|
|
|
clear_workbase(tmp); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
HASH_ADD_INT(workbases, id, wb); |
|
|
|
|
|
|
|
current_workbase = wb; |
|
|
|
|
|
|
|
ck_wunlock(&workbase_lock); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (*new_block) |
|
|
|
|
|
|
|
purge_share_hashtable(wb->id); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* This function assumes it will only receive a valid json gbt base template
|
|
|
|
/* This function assumes it will only receive a valid json gbt base template
|
|
|
|
* since checking should have been done earlier, and creates the base template |
|
|
|
* since checking should have been done earlier, and creates the base template |
|
|
|
* for generating work templates. */ |
|
|
|
* for generating work templates. */ |
|
|
|
static void update_base(ckpool_t *ckp) |
|
|
|
static void update_base(ckpool_t *ckp) |
|
|
|
{ |
|
|
|
{ |
|
|
|
workbase_t *wb, *tmp, *tmpa; |
|
|
|
|
|
|
|
bool new_block = false; |
|
|
|
bool new_block = false; |
|
|
|
int len, ret; |
|
|
|
workbase_t *wb; |
|
|
|
json_t *val; |
|
|
|
json_t *val; |
|
|
|
char *buf; |
|
|
|
char *buf; |
|
|
|
|
|
|
|
|
|
|
@ -396,46 +445,8 @@ static void update_base(ckpool_t *ckp) |
|
|
|
} |
|
|
|
} |
|
|
|
json_decref(val); |
|
|
|
json_decref(val); |
|
|
|
generate_coinbase(ckp, wb); |
|
|
|
generate_coinbase(ckp, wb); |
|
|
|
wb->gentime = time(NULL); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
len = strlen(ckp->logdir) + 8 + 1 + 16; |
|
|
|
add_base(ckp, wb, &new_block); |
|
|
|
wb->logdir = ckalloc(len); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ck_wlock(&workbase_lock); |
|
|
|
|
|
|
|
wb->id = workbase_id++; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (strncmp(wb->prevhash, lasthash, 64)) { |
|
|
|
|
|
|
|
new_block = true; |
|
|
|
|
|
|
|
memcpy(lasthash, wb->prevhash, 65); |
|
|
|
|
|
|
|
blockchange_id = wb->id; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (new_block) { |
|
|
|
|
|
|
|
sprintf(wb->logdir, "%s%08x/", ckp->logdir, wb->height); |
|
|
|
|
|
|
|
ret = mkdir(wb->logdir, 0700); |
|
|
|
|
|
|
|
if (unlikely(ret && errno != EEXIST)) |
|
|
|
|
|
|
|
quit(1, "Failed to create log directory %s", wb->logdir); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
sprintf(wb->idstring, "%016lx", wb->id); |
|
|
|
|
|
|
|
/* Do not store the trailing slash for the subdir */ |
|
|
|
|
|
|
|
sprintf(wb->logdir, "%s%08x/%s", ckp->logdir, wb->height, wb->idstring); |
|
|
|
|
|
|
|
ret = mkdir(wb->logdir, 0700); |
|
|
|
|
|
|
|
if (unlikely(ret && errno != EEXIST)) |
|
|
|
|
|
|
|
quit(1, "Failed to create log directory %s", wb->logdir); |
|
|
|
|
|
|
|
HASH_ITER(hh, workbases, tmp, tmpa) { |
|
|
|
|
|
|
|
if (HASH_COUNT(workbases) < 3) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
/* Age old workbases older than 10 minutes old */ |
|
|
|
|
|
|
|
if (tmp->gentime < wb->gentime - 600) { |
|
|
|
|
|
|
|
HASH_DEL(workbases, tmp); |
|
|
|
|
|
|
|
clear_workbase(tmp); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
HASH_ADD_INT(workbases, id, wb); |
|
|
|
|
|
|
|
current_workbase = wb; |
|
|
|
|
|
|
|
ck_wunlock(&workbase_lock); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (new_block) |
|
|
|
|
|
|
|
purge_share_hashtable(wb->id); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stratum_broadcast_update(new_block); |
|
|
|
stratum_broadcast_update(new_block); |
|
|
|
} |
|
|
|
} |
|
|
@ -459,11 +470,14 @@ static bool update_subscribe(ckpool_t *ckp) |
|
|
|
proxy_base.diff = 1; |
|
|
|
proxy_base.diff = 1; |
|
|
|
/* Length is checked by generator */ |
|
|
|
/* Length is checked by generator */ |
|
|
|
strcpy(proxy_base.enonce1, json_string_value(json_object_get(val, "enonce1"))); |
|
|
|
strcpy(proxy_base.enonce1, json_string_value(json_object_get(val, "enonce1"))); |
|
|
|
|
|
|
|
proxy_base.enonce1constlen = strlen(proxy_base.enonce1) / 2; |
|
|
|
|
|
|
|
hex2bin(proxy_base.enonce1bin, proxy_base.enonce1, proxy_base.enonce1constlen); |
|
|
|
proxy_base.nonce2len = json_integer_value(json_object_get(val, "nonce2len")); |
|
|
|
proxy_base.nonce2len = json_integer_value(json_object_get(val, "nonce2len")); |
|
|
|
if (proxy_base.nonce2len > 5) |
|
|
|
if (proxy_base.nonce2len > 5) |
|
|
|
proxy_base.subnonce2len = 4; |
|
|
|
proxy_base.enonce2constlen = 4; |
|
|
|
else |
|
|
|
else |
|
|
|
proxy_base.subnonce2len = 2; |
|
|
|
proxy_base.enonce2constlen = 2; |
|
|
|
|
|
|
|
proxy_base.enonce2varlen = proxy_base.nonce2len - proxy_base.enonce2constlen; |
|
|
|
ck_wunlock(&workbase_lock); |
|
|
|
ck_wunlock(&workbase_lock); |
|
|
|
|
|
|
|
|
|
|
|
json_decref(val); |
|
|
|
json_decref(val); |
|
|
@ -472,15 +486,65 @@ static bool update_subscribe(ckpool_t *ckp) |
|
|
|
|
|
|
|
|
|
|
|
static void update_notify(ckpool_t *ckp) |
|
|
|
static void update_notify(ckpool_t *ckp) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
bool new_block = false, clean; |
|
|
|
|
|
|
|
char header[228]; |
|
|
|
|
|
|
|
workbase_t *wb; |
|
|
|
|
|
|
|
json_t *val; |
|
|
|
char *buf; |
|
|
|
char *buf; |
|
|
|
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
|
|
buf = send_recv_proc(ckp->generator, "getnotify"); |
|
|
|
buf = send_recv_proc(ckp->generator, "getnotify"); |
|
|
|
if (unlikely(!buf)) { |
|
|
|
if (unlikely(!buf)) { |
|
|
|
LOGWARNING("Failed to get notify from generator in update_notify"); |
|
|
|
LOGWARNING("Failed to get notify from generator in update_notify"); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
LOGWARNING("Notify was %s", buf); |
|
|
|
|
|
|
|
free(buf); |
|
|
|
LOGDEBUG("Update notify: %s", buf); |
|
|
|
|
|
|
|
wb = ckzalloc(sizeof(workbase_t)); |
|
|
|
|
|
|
|
wb->ckp = ckp; |
|
|
|
|
|
|
|
val = json_loads(buf, 0, NULL); |
|
|
|
|
|
|
|
dealloc(buf); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
json_uint64cpy(&wb->id, val, "jobid"); |
|
|
|
|
|
|
|
json_strcpy(wb->prevhash, val, "prevhash"); |
|
|
|
|
|
|
|
json_strcpy(wb->coinb1, val, "coinbase1"); |
|
|
|
|
|
|
|
wb->coinb1len = strlen(wb->coinb1) / 2; |
|
|
|
|
|
|
|
hex2bin(wb->coinb1bin, wb->coinb1, wb->coinb1len); |
|
|
|
|
|
|
|
json_strcpy(wb->coinb2, val, "coinbase2"); |
|
|
|
|
|
|
|
wb->coinb2len = strlen(wb->coinb2) / 2; |
|
|
|
|
|
|
|
hex2bin(wb->coinb2bin, wb->coinb2, wb->coinb2len); |
|
|
|
|
|
|
|
wb->merkle_array = json_copy(json_object_get(val, "merklehash")); |
|
|
|
|
|
|
|
wb->merkles = json_array_size(wb->merkle_array); |
|
|
|
|
|
|
|
for (i = 0; i < wb->merkles; i++) { |
|
|
|
|
|
|
|
strcpy(&wb->merklehash[i][0], json_string_value(json_array_get(wb->merkle_array, i))); |
|
|
|
|
|
|
|
hex2bin(&wb->merklebin[i][0], &wb->merklehash[i][0], 32); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
json_strcpy(wb->bbversion, val, "bbversion"); |
|
|
|
|
|
|
|
json_strcpy(wb->nbit, val, "nbit"); |
|
|
|
|
|
|
|
json_strcpy(wb->ntime, val, "ntime"); |
|
|
|
|
|
|
|
clean = json_is_true(json_object_get(val, "clean")); |
|
|
|
|
|
|
|
json_decref(val); |
|
|
|
|
|
|
|
wb->gentime = time(NULL); |
|
|
|
|
|
|
|
wb->enonce1varlen = 0; |
|
|
|
|
|
|
|
snprintf(header, 225, "%s%s%s%s%s%s%s", |
|
|
|
|
|
|
|
wb->bbversion, wb->prevhash, |
|
|
|
|
|
|
|
"0000000000000000000000000000000000000000000000000000000000000000", |
|
|
|
|
|
|
|
wb->ntime, wb->nbit, |
|
|
|
|
|
|
|
"00000000", /* nonce */ |
|
|
|
|
|
|
|
workpadding); |
|
|
|
|
|
|
|
LOGDEBUG("Header: %s", header); |
|
|
|
|
|
|
|
hex2bin(wb->headerbin, header, 112); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ck_rlock(&workbase_lock); |
|
|
|
|
|
|
|
strcpy(wb->enonce1const, proxy_base.enonce1); |
|
|
|
|
|
|
|
memcpy(wb->enonce1constbin, proxy_base.enonce1bin, proxy_base.enonce1constlen); |
|
|
|
|
|
|
|
wb->enonce1varlen = wb->enonce2constlen = proxy_base.enonce2constlen; |
|
|
|
|
|
|
|
wb->enonce2varlen = proxy_base.enonce2varlen; |
|
|
|
|
|
|
|
ck_runlock(&workbase_lock); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
add_base(ckp, wb, &new_block); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stratum_broadcast_update(new_block | clean); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Enter with instance_lock held */ |
|
|
|
/* Enter with instance_lock held */ |
|
|
|