|
|
|
@ -1202,6 +1202,193 @@ static void add_node_base(ckpool_t *ckp, json_t *val)
|
|
|
|
|
LOGNOTICE("Block hash changed to %s", sdata->lastswaphash); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Calculate share diff and fill in hash and swap */ |
|
|
|
|
static double |
|
|
|
|
share_diff(char *coinbase, const uchar *enonce1bin, const workbase_t *wb, const char *nonce2, |
|
|
|
|
const uint32_t ntime32, const char *nonce, uchar *hash, uchar *swap, int *cblen) |
|
|
|
|
{ |
|
|
|
|
unsigned char merkle_root[32], merkle_sha[64]; |
|
|
|
|
uint32_t *data32, *swap32, benonce32; |
|
|
|
|
uchar hash1[32]; |
|
|
|
|
char data[80]; |
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
memcpy(coinbase, wb->coinb1bin, wb->coinb1len); |
|
|
|
|
*cblen = wb->coinb1len; |
|
|
|
|
memcpy(coinbase + *cblen, enonce1bin, wb->enonce1constlen + wb->enonce1varlen); |
|
|
|
|
*cblen += wb->enonce1constlen + wb->enonce1varlen; |
|
|
|
|
hex2bin(coinbase + *cblen, nonce2, wb->enonce2varlen); |
|
|
|
|
*cblen += wb->enonce2varlen; |
|
|
|
|
memcpy(coinbase + *cblen, wb->coinb2bin, wb->coinb2len); |
|
|
|
|
*cblen += wb->coinb2len; |
|
|
|
|
|
|
|
|
|
gen_hash((uchar *)coinbase, merkle_root, *cblen); |
|
|
|
|
memcpy(merkle_sha, merkle_root, 32); |
|
|
|
|
for (i = 0; i < wb->merkles; i++) { |
|
|
|
|
memcpy(merkle_sha + 32, &wb->merklebin[i], 32); |
|
|
|
|
gen_hash(merkle_sha, merkle_root, 64); |
|
|
|
|
memcpy(merkle_sha, merkle_root, 32); |
|
|
|
|
} |
|
|
|
|
data32 = (uint32_t *)merkle_sha; |
|
|
|
|
swap32 = (uint32_t *)merkle_root; |
|
|
|
|
flip_32(swap32, data32); |
|
|
|
|
|
|
|
|
|
/* Copy the cached header binary and insert the merkle root */ |
|
|
|
|
memcpy(data, wb->headerbin, 80); |
|
|
|
|
memcpy(data + 36, merkle_root, 32); |
|
|
|
|
|
|
|
|
|
/* Insert the nonce value into the data */ |
|
|
|
|
hex2bin(&benonce32, nonce, 4); |
|
|
|
|
data32 = (uint32_t *)(data + 64 + 12); |
|
|
|
|
*data32 = benonce32; |
|
|
|
|
|
|
|
|
|
/* Insert the ntime value into the data */ |
|
|
|
|
data32 = (uint32_t *)(data + 68); |
|
|
|
|
*data32 = htobe32(ntime32); |
|
|
|
|
|
|
|
|
|
/* Hash the share */ |
|
|
|
|
data32 = (uint32_t *)data; |
|
|
|
|
swap32 = (uint32_t *)swap; |
|
|
|
|
flip_80(swap32, data32); |
|
|
|
|
sha256(swap, 80, hash1); |
|
|
|
|
sha256(hash1, 32, hash); |
|
|
|
|
|
|
|
|
|
/* Calculate the diff of the share here */ |
|
|
|
|
return diff_from_target(hash); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
process_block(ckpool_t *ckp, const workbase_t *wb, const char *coinbase, const int cblen, |
|
|
|
|
const uchar *data, const uchar *hash, uchar *swap32, char *blockhash) |
|
|
|
|
{ |
|
|
|
|
int transactions = wb->transactions + 1; |
|
|
|
|
char *gbt_block, varint[12]; |
|
|
|
|
char hexcoinbase[1024]; |
|
|
|
|
|
|
|
|
|
gbt_block = ckalloc(1024); |
|
|
|
|
flip_32(swap32, hash); |
|
|
|
|
__bin2hex(blockhash, swap32, 32); |
|
|
|
|
|
|
|
|
|
/* Message format: "submitblock:hash,data" */ |
|
|
|
|
sprintf(gbt_block, "submitblock:%s,", blockhash); |
|
|
|
|
__bin2hex(gbt_block + 12 + 64 + 1, data, 80); |
|
|
|
|
if (transactions < 0xfd) { |
|
|
|
|
uint8_t val8 = transactions; |
|
|
|
|
|
|
|
|
|
__bin2hex(varint, (const unsigned char *)&val8, 1); |
|
|
|
|
} else if (transactions <= 0xffff) { |
|
|
|
|
uint16_t val16 = htole16(transactions); |
|
|
|
|
|
|
|
|
|
strcat(gbt_block, "fd"); |
|
|
|
|
__bin2hex(varint, (const unsigned char *)&val16, 2); |
|
|
|
|
} else { |
|
|
|
|
uint32_t val32 = htole32(transactions); |
|
|
|
|
|
|
|
|
|
strcat(gbt_block, "fe"); |
|
|
|
|
__bin2hex(varint, (const unsigned char *)&val32, 4); |
|
|
|
|
} |
|
|
|
|
strcat(gbt_block, varint); |
|
|
|
|
__bin2hex(hexcoinbase, coinbase, cblen); |
|
|
|
|
strcat(gbt_block, hexcoinbase); |
|
|
|
|
if (wb->transactions) |
|
|
|
|
realloc_strcat(&gbt_block, wb->txn_data); |
|
|
|
|
send_generator(ckp, gbt_block, GEN_PRIORITY); |
|
|
|
|
free(gbt_block); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void submit_node_block(ckpool_t *ckp, sdata_t *sdata, json_t *val) |
|
|
|
|
{ |
|
|
|
|
char *coinbase = NULL, *enonce1 = NULL, *nonce = NULL, *nonce2 = NULL; |
|
|
|
|
uchar *enonce1bin = NULL, hash[32], swap[80], swap32[32]; |
|
|
|
|
char blockhash[68], cdfield[64]; |
|
|
|
|
int enonce1len, cblen; |
|
|
|
|
ckmsg_t *block_ckmsg; |
|
|
|
|
json_t *bval = NULL; |
|
|
|
|
uint32_t ntime32; |
|
|
|
|
workbase_t *wb; |
|
|
|
|
double diff; |
|
|
|
|
ts_t ts_now; |
|
|
|
|
int64_t id; |
|
|
|
|
|
|
|
|
|
if (unlikely(!json_get_string(&enonce1, val, "enonce1"))) { |
|
|
|
|
LOGWARNING("Failed to get enonce1 from node method block"); |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
if (unlikely(!json_get_string(&nonce, val, "nonce"))) { |
|
|
|
|
LOGWARNING("Failed to get nonce from node method block"); |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
if (unlikely(!json_get_string(&nonce2, val, "nonce2"))) { |
|
|
|
|
LOGWARNING("Failed to get nonce2 from node method block"); |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
if (unlikely(!json_get_uint32(&ntime32, val, "ntime32"))) { |
|
|
|
|
LOGWARNING("Failed to get ntime32 from node method block"); |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
if (unlikely(!json_get_int64(&id, val, "jobid"))) { |
|
|
|
|
LOGWARNING("Failed to get jobid from node method block"); |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
if (unlikely(!json_get_double(&diff, val, "diff"))) { |
|
|
|
|
LOGWARNING("Failed to get diff from node method block"); |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ts_realtime(&ts_now); |
|
|
|
|
sprintf(cdfield, "%lu,%lu", ts_now.tv_sec, ts_now.tv_nsec); |
|
|
|
|
|
|
|
|
|
ck_rlock(&sdata->workbase_lock); |
|
|
|
|
HASH_FIND_I64(sdata->workbases, &id, wb); |
|
|
|
|
if (unlikely(!wb)) |
|
|
|
|
goto out_unlock; |
|
|
|
|
/* Now we have enough to assemble a block */ |
|
|
|
|
coinbase = ckalloc(wb->coinb1len + wb->enonce1constlen + wb->enonce1varlen + wb->enonce2varlen + wb->coinb2len); |
|
|
|
|
enonce1len = wb->enonce1constlen + wb->enonce1varlen; |
|
|
|
|
enonce1bin = ckalloc(enonce1len); |
|
|
|
|
hex2bin(enonce1bin, enonce1, enonce1len); |
|
|
|
|
|
|
|
|
|
/* Fill in the hashes */ |
|
|
|
|
share_diff(coinbase, enonce1bin, wb, nonce2, ntime32, nonce, hash, swap, &cblen); |
|
|
|
|
process_block(ckp, wb, coinbase, cblen, swap, hash, swap32, blockhash); |
|
|
|
|
|
|
|
|
|
JSON_CPACK(bval, "{si,ss,ss,sI,ss,ss,ss,sI,sf,ss,ss,ss,ss}", |
|
|
|
|
"height", wb->height, |
|
|
|
|
"blockhash", blockhash, |
|
|
|
|
"confirmed", "n", |
|
|
|
|
"workinfoid", wb->id, |
|
|
|
|
"enonce1", enonce1, |
|
|
|
|
"nonce2", nonce2, |
|
|
|
|
"nonce", nonce, |
|
|
|
|
"reward", wb->coinbasevalue, |
|
|
|
|
"diff", diff, |
|
|
|
|
"createdate", cdfield, |
|
|
|
|
"createby", "code", |
|
|
|
|
"createcode", __func__, |
|
|
|
|
"createinet", ckp->serverurl[0]); |
|
|
|
|
out_unlock: |
|
|
|
|
ck_runlock(&sdata->workbase_lock); |
|
|
|
|
|
|
|
|
|
if (unlikely(!wb)) |
|
|
|
|
LOGWARNING("Failed to find workbase with jobid %"PRId64" in node method block", id); |
|
|
|
|
else { |
|
|
|
|
block_ckmsg = ckalloc(sizeof(ckmsg_t)); |
|
|
|
|
block_ckmsg->data = bval; |
|
|
|
|
|
|
|
|
|
mutex_lock(&sdata->block_lock); |
|
|
|
|
DL_APPEND(sdata->block_solves, block_ckmsg); |
|
|
|
|
mutex_unlock(&sdata->block_lock); |
|
|
|
|
|
|
|
|
|
ckdbq_add(ckp, ID_BLOCK, bval); |
|
|
|
|
} |
|
|
|
|
out: |
|
|
|
|
free(enonce1bin); |
|
|
|
|
free(coinbase); |
|
|
|
|
free(nonce2); |
|
|
|
|
free(nonce); |
|
|
|
|
free(enonce1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void update_base(ckpool_t *ckp, const int prio) |
|
|
|
|
{ |
|
|
|
|
struct update_req *ur = ckalloc(sizeof(struct update_req)); |
|
|
|
@ -4621,15 +4808,12 @@ test_blocksolve(const stratum_instance_t *client, const workbase_t *wb, const uc
|
|
|
|
|
const uchar *hash, const double diff, const char *coinbase, int cblen, |
|
|
|
|
const char *nonce2, const char *nonce) |
|
|
|
|
{ |
|
|
|
|
int transactions = wb->transactions + 1; |
|
|
|
|
char hexcoinbase[1024], blockhash[68]; |
|
|
|
|
char blockhash[68], cdfield[64]; |
|
|
|
|
sdata_t *sdata = client->sdata; |
|
|
|
|
json_t *val = NULL, *val_copy; |
|
|
|
|
char *gbt_block, varint[12]; |
|
|
|
|
ckpool_t *ckp = wb->ckp; |
|
|
|
|
ckmsg_t *block_ckmsg; |
|
|
|
|
char cdfield[64]; |
|
|
|
|
uchar swap[32]; |
|
|
|
|
uchar swap32[32]; |
|
|
|
|
ts_t ts_now; |
|
|
|
|
|
|
|
|
|
/* Submit anything over 99.9% of the diff in case of rounding errors */ |
|
|
|
@ -4644,35 +4828,7 @@ test_blocksolve(const stratum_instance_t *client, const workbase_t *wb, const uc
|
|
|
|
|
ts_realtime(&ts_now); |
|
|
|
|
sprintf(cdfield, "%lu,%lu", ts_now.tv_sec, ts_now.tv_nsec); |
|
|
|
|
|
|
|
|
|
gbt_block = ckalloc(1024); |
|
|
|
|
flip_32(swap, hash); |
|
|
|
|
__bin2hex(blockhash, swap, 32); |
|
|
|
|
|
|
|
|
|
/* Message format: "submitblock:hash,data" */ |
|
|
|
|
sprintf(gbt_block, "submitblock:%s,", blockhash); |
|
|
|
|
__bin2hex(gbt_block + 12 + 64 + 1, data, 80); |
|
|
|
|
if (transactions < 0xfd) { |
|
|
|
|
uint8_t val8 = transactions; |
|
|
|
|
|
|
|
|
|
__bin2hex(varint, (const unsigned char *)&val8, 1); |
|
|
|
|
} else if (transactions <= 0xffff) { |
|
|
|
|
uint16_t val16 = htole16(transactions); |
|
|
|
|
|
|
|
|
|
strcat(gbt_block, "fd"); |
|
|
|
|
__bin2hex(varint, (const unsigned char *)&val16, 2); |
|
|
|
|
} else { |
|
|
|
|
uint32_t val32 = htole32(transactions); |
|
|
|
|
|
|
|
|
|
strcat(gbt_block, "fe"); |
|
|
|
|
__bin2hex(varint, (const unsigned char *)&val32, 4); |
|
|
|
|
} |
|
|
|
|
strcat(gbt_block, varint); |
|
|
|
|
__bin2hex(hexcoinbase, coinbase, cblen); |
|
|
|
|
strcat(gbt_block, hexcoinbase); |
|
|
|
|
if (wb->transactions) |
|
|
|
|
realloc_strcat(&gbt_block, wb->txn_data); |
|
|
|
|
send_generator(ckp, gbt_block, GEN_PRIORITY); |
|
|
|
|
free(gbt_block); |
|
|
|
|
process_block(ckp, wb, coinbase, cblen, data, hash, swap32, blockhash); |
|
|
|
|
|
|
|
|
|
JSON_CPACK(val, "{si,ss,ss,sI,ss,ss,sI,ss,ss,ss,sI,ss,ss,ss,ss}", |
|
|
|
|
"height", wb->height, |
|
|
|
@ -4702,61 +4858,6 @@ test_blocksolve(const stratum_instance_t *client, const workbase_t *wb, const uc
|
|
|
|
|
ckdbq_add(ckp, ID_BLOCK, val); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Calculate share diff and fill in hash and swap */ |
|
|
|
|
static double |
|
|
|
|
share_diff(char *coinbase, const uchar *enonce1bin, const workbase_t *wb, const char *nonce2, |
|
|
|
|
const uint32_t ntime32, const char *nonce, uchar *hash, uchar *swap, int *cblen) |
|
|
|
|
{ |
|
|
|
|
unsigned char merkle_root[32], merkle_sha[64]; |
|
|
|
|
uint32_t *data32, *swap32, benonce32; |
|
|
|
|
uchar hash1[32]; |
|
|
|
|
char data[80]; |
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
memcpy(coinbase, wb->coinb1bin, wb->coinb1len); |
|
|
|
|
*cblen = wb->coinb1len; |
|
|
|
|
memcpy(coinbase + *cblen, enonce1bin, wb->enonce1constlen + wb->enonce1varlen); |
|
|
|
|
*cblen += wb->enonce1constlen + wb->enonce1varlen; |
|
|
|
|
hex2bin(coinbase + *cblen, nonce2, wb->enonce2varlen); |
|
|
|
|
*cblen += wb->enonce2varlen; |
|
|
|
|
memcpy(coinbase + *cblen, wb->coinb2bin, wb->coinb2len); |
|
|
|
|
*cblen += wb->coinb2len; |
|
|
|
|
|
|
|
|
|
gen_hash((uchar *)coinbase, merkle_root, *cblen); |
|
|
|
|
memcpy(merkle_sha, merkle_root, 32); |
|
|
|
|
for (i = 0; i < wb->merkles; i++) { |
|
|
|
|
memcpy(merkle_sha + 32, &wb->merklebin[i], 32); |
|
|
|
|
gen_hash(merkle_sha, merkle_root, 64); |
|
|
|
|
memcpy(merkle_sha, merkle_root, 32); |
|
|
|
|
} |
|
|
|
|
data32 = (uint32_t *)merkle_sha; |
|
|
|
|
swap32 = (uint32_t *)merkle_root; |
|
|
|
|
flip_32(swap32, data32); |
|
|
|
|
|
|
|
|
|
/* Copy the cached header binary and insert the merkle root */ |
|
|
|
|
memcpy(data, wb->headerbin, 80); |
|
|
|
|
memcpy(data + 36, merkle_root, 32); |
|
|
|
|
|
|
|
|
|
/* Insert the nonce value into the data */ |
|
|
|
|
hex2bin(&benonce32, nonce, 4); |
|
|
|
|
data32 = (uint32_t *)(data + 64 + 12); |
|
|
|
|
*data32 = benonce32; |
|
|
|
|
|
|
|
|
|
/* Insert the ntime value into the data */ |
|
|
|
|
data32 = (uint32_t *)(data + 68); |
|
|
|
|
*data32 = htobe32(ntime32); |
|
|
|
|
|
|
|
|
|
/* Hash the share */ |
|
|
|
|
data32 = (uint32_t *)data; |
|
|
|
|
swap32 = (uint32_t *)swap; |
|
|
|
|
flip_80(swap32, data32); |
|
|
|
|
sha256(swap, 80, hash1); |
|
|
|
|
sha256(hash1, 32, hash); |
|
|
|
|
|
|
|
|
|
/* Calculate the diff of the share here */ |
|
|
|
|
return diff_from_target(hash); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Needs to be entered with client holding a ref count. */ |
|
|
|
|
static double submission_diff(const stratum_instance_t *client, const workbase_t *wb, const char *nonce2, |
|
|
|
|
const uint32_t ntime32, const char *nonce, uchar *hash) |
|
|
|
@ -5711,7 +5812,7 @@ static void node_client_msg(ckpool_t *ckp, json_t *val, const char *buf, stratum
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void parse_node_msg(ckpool_t *ckp, json_t *val, const char *buf) |
|
|
|
|
static void parse_node_msg(ckpool_t *ckp, sdata_t *sdata, json_t *val, const char *buf) |
|
|
|
|
{ |
|
|
|
|
int msg_type = node_msg_type(val); |
|
|
|
|
|
|
|
|
@ -5724,6 +5825,9 @@ static void parse_node_msg(ckpool_t *ckp, json_t *val, const char *buf)
|
|
|
|
|
case SM_WORKINFO: |
|
|
|
|
add_node_base(ckp, val); |
|
|
|
|
break; |
|
|
|
|
case SM_BLOCK: |
|
|
|
|
submit_node_block(ckp, sdata, val); |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
@ -5804,7 +5908,7 @@ static void srecv_process(ckpool_t *ckp, char *buf)
|
|
|
|
|
val = json_object_get(msg->json_msg, "client_id"); |
|
|
|
|
if (unlikely(!val)) { |
|
|
|
|
if (ckp->node) |
|
|
|
|
parse_node_msg(ckp, msg->json_msg, buf); |
|
|
|
|
parse_node_msg(ckp, sdata, msg->json_msg, buf); |
|
|
|
|
else |
|
|
|
|
LOGWARNING("Failed to extract client_id from connector json smsg %s", buf); |
|
|
|
|
json_decref(msg->json_msg); |
|
|
|
|