diff --git a/src/ckpool.c b/src/ckpool.c index b3259661..ee54a7a2 100644 --- a/src/ckpool.c +++ b/src/ckpool.c @@ -1274,6 +1274,26 @@ out: return ret; } +bool json_get_uint32(uint32_t *store, const json_t *val, const char *res) +{ + json_t *entry = json_object_get(val, res); + bool ret = false; + + if (!entry) { + LOGDEBUG("Json did not find entry %s", res); + goto out; + } + if (!json_is_integer(entry)) { + LOGWARNING("Json entry %s is not an integer", res); + goto out; + } + *store = json_integer_value(entry); + LOGDEBUG("Json found entry %s: %u", res, *store); + ret = true; +out: + return ret; +} + bool json_get_bool(bool *store, const json_t *val, const char *res) { json_t *entry = json_object_get(val, res); diff --git a/src/ckpool.h b/src/ckpool.h index 894661e5..cc3a7968 100644 --- a/src/ckpool.h +++ b/src/ckpool.h @@ -267,6 +267,7 @@ enum stratum_msgtype { SM_PING, SM_WORKINFO, SM_SUGGESTDIFF, + SM_BLOCK, SM_NONE }; @@ -287,6 +288,7 @@ static const char __maybe_unused *stratum_msgs[] = { "ping", "workinfo", "suggestdiff", + "block", "" }; @@ -331,6 +333,7 @@ bool json_get_string(char **store, const json_t *val, const char *res); bool json_get_int64(int64_t *store, const json_t *val, const char *res); bool json_get_int(int *store, const json_t *val, const char *res); bool json_get_double(double *store, const json_t *val, const char *res); +bool json_get_uint32(uint32_t *store, const json_t *val, const char *res); bool json_get_bool(bool *store, const json_t *val, const char *res); bool json_getdel_int(int *store, json_t *val, const char *res); bool json_getdel_int64(int64_t *store, json_t *val, const char *res); diff --git a/src/stratifier.c b/src/stratifier.c index 4a4e87b9..778eb1db 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -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);