Browse Source

Add mechanism for parsing received block messages from the main pool at remote nodes to submit them locally

master
Con Kolivas 9 years ago
parent
commit
7b887e9ac6
  1. 20
      src/ckpool.c
  2. 3
      src/ckpool.h
  3. 286
      src/stratifier.c

20
src/ckpool.c

@ -1274,6 +1274,26 @@ out:
return ret; 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) bool json_get_bool(bool *store, const json_t *val, const char *res)
{ {
json_t *entry = json_object_get(val, res); json_t *entry = json_object_get(val, res);

3
src/ckpool.h

@ -267,6 +267,7 @@ enum stratum_msgtype {
SM_PING, SM_PING,
SM_WORKINFO, SM_WORKINFO,
SM_SUGGESTDIFF, SM_SUGGESTDIFF,
SM_BLOCK,
SM_NONE SM_NONE
}; };
@ -287,6 +288,7 @@ static const char __maybe_unused *stratum_msgs[] = {
"ping", "ping",
"workinfo", "workinfo",
"suggestdiff", "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_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_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_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_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_int(int *store, json_t *val, const char *res);
bool json_getdel_int64(int64_t *store, json_t *val, const char *res); bool json_getdel_int64(int64_t *store, json_t *val, const char *res);

286
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); 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) static void update_base(ckpool_t *ckp, const int prio)
{ {
struct update_req *ur = ckalloc(sizeof(struct update_req)); 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 uchar *hash, const double diff, const char *coinbase, int cblen,
const char *nonce2, const char *nonce) const char *nonce2, const char *nonce)
{ {
int transactions = wb->transactions + 1; char blockhash[68], cdfield[64];
char hexcoinbase[1024], blockhash[68];
sdata_t *sdata = client->sdata; sdata_t *sdata = client->sdata;
json_t *val = NULL, *val_copy; json_t *val = NULL, *val_copy;
char *gbt_block, varint[12];
ckpool_t *ckp = wb->ckp; ckpool_t *ckp = wb->ckp;
ckmsg_t *block_ckmsg; ckmsg_t *block_ckmsg;
char cdfield[64]; uchar swap32[32];
uchar swap[32];
ts_t ts_now; ts_t ts_now;
/* Submit anything over 99.9% of the diff in case of rounding errors */ /* 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); ts_realtime(&ts_now);
sprintf(cdfield, "%lu,%lu", ts_now.tv_sec, ts_now.tv_nsec); sprintf(cdfield, "%lu,%lu", ts_now.tv_sec, ts_now.tv_nsec);
gbt_block = ckalloc(1024); process_block(ckp, wb, coinbase, cblen, data, hash, swap32, blockhash);
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);
JSON_CPACK(val, "{si,ss,ss,sI,ss,ss,sI,ss,ss,ss,sI,ss,ss,ss,ss}", JSON_CPACK(val, "{si,ss,ss,sI,ss,ss,sI,ss,ss,ss,sI,ss,ss,ss,ss}",
"height", wb->height, "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); 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. */ /* 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, 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) 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); 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: case SM_WORKINFO:
add_node_base(ckp, val); add_node_base(ckp, val);
break; break;
case SM_BLOCK:
submit_node_block(ckp, sdata, val);
break;
default: default:
break; break;
} }
@ -5804,7 +5908,7 @@ static void srecv_process(ckpool_t *ckp, char *buf)
val = json_object_get(msg->json_msg, "client_id"); val = json_object_get(msg->json_msg, "client_id");
if (unlikely(!val)) { if (unlikely(!val)) {
if (ckp->node) if (ckp->node)
parse_node_msg(ckp, msg->json_msg, buf); parse_node_msg(ckp, sdata, msg->json_msg, buf);
else else
LOGWARNING("Failed to extract client_id from connector json smsg %s", buf); LOGWARNING("Failed to extract client_id from connector json smsg %s", buf);
json_decref(msg->json_msg); json_decref(msg->json_msg);

Loading…
Cancel
Save