Browse Source

Support virtual mask changing of the version bits by clients according to a hex config parameter version_mask.

master
Con Kolivas 7 years ago
parent
commit
f642c515df
  1. 4
      README
  2. 1
      ckpool.conf
  3. 5
      src/ckpool.c
  4. 3
      src/ckpool.h
  5. 6
      src/libckpool.h
  6. 84
      src/stratifier.c

4
README

@ -286,6 +286,10 @@ from 2 to 8. Default 8
miners and is set to 30 seconds by default to help perpetuate transactions for miners and is set to 30 seconds by default to help perpetuate transactions for
the health of the bitcoin network. the health of the bitcoin network.
"version_mask" : This is a mask of which bits in the version number it is valid
for a client to alter and is expressed as an hex string. Eg "7FFFFFFB"
Default is "00000000".
"serverurl" : This is the IP(s) to try to bind ckpool uniquely to, otherwise it "serverurl" : This is the IP(s) to try to bind ckpool uniquely to, otherwise it
will attempt to bind to all interfaces in port 3333 by default in pool mode will attempt to bind to all interfaces in port 3333 by default in pool mode
and 3334 in proxy mode. Multiple entries can be specified as an array by and 3334 in proxy mode. Multiple entries can be specified as an array by

1
ckpool.conf

@ -20,6 +20,7 @@
"nonce1length" : 4, "nonce1length" : 4,
"nonce2length" : 8, "nonce2length" : 8,
"update_interval" : 30, "update_interval" : 30,
"version_mask" : "00000000",
"serverurl" : [ "serverurl" : [
"ckpool.org:3333", "ckpool.org:3333",
"node.ckpool.org:3333", "node.ckpool.org:3333",

5
src/ckpool.c

@ -1444,8 +1444,8 @@ static void parse_config(ckpool_t *ckp)
{ {
json_t *json_conf, *arr_val; json_t *json_conf, *arr_val;
json_error_t err_val; json_error_t err_val;
char *url, *vmask;
int arr_size; int arr_size;
char *url;
json_conf = json_load_file(ckp->config, JSON_DISABLE_EOF_CHECK, &err_val); json_conf = json_load_file(ckp->config, JSON_DISABLE_EOF_CHECK, &err_val);
if (!json_conf) { if (!json_conf) {
@ -1469,6 +1469,9 @@ static void parse_config(ckpool_t *ckp)
json_get_int(&ckp->nonce1length, json_conf, "nonce1length"); json_get_int(&ckp->nonce1length, json_conf, "nonce1length");
json_get_int(&ckp->nonce2length, json_conf, "nonce2length"); json_get_int(&ckp->nonce2length, json_conf, "nonce2length");
json_get_int(&ckp->update_interval, json_conf, "update_interval"); json_get_int(&ckp->update_interval, json_conf, "update_interval");
json_get_string(&vmask, json_conf, "version_mask");
if (vmask && strlen(vmask) && validhex(vmask))
sscanf(vmask, "%x", &ckp->version_mask);
/* Look for an array first and then a single entry */ /* Look for an array first and then a single entry */
arr_val = json_object_get(json_conf, "serverurl"); arr_val = json_object_get(json_conf, "serverurl");
if (!parse_serverurls(ckp, arr_val)) { if (!parse_serverurls(ckp, arr_val)) {

3
src/ckpool.h

@ -255,6 +255,8 @@ struct ckpool_instance {
int update_interval; // Seconds between stratum updates int update_interval; // Seconds between stratum updates
uint32_t version_mask; // Bits which set to true means allow miner to modify those bits
/* Proxy options */ /* Proxy options */
int proxies; int proxies;
char **proxyurl; char **proxyurl;
@ -295,6 +297,7 @@ enum stratum_msgtype {
SM_SHAREERR, SM_SHAREERR,
SM_WORKERSTATS, SM_WORKERSTATS,
SM_REQTXNS, SM_REQTXNS,
SM_VERSIONMASK,
SM_NONE SM_NONE
}; };

6
src/libckpool.h

@ -267,7 +267,8 @@ enum share_err {
SE_STALE, SE_STALE,
SE_NTIME_INVALID, SE_NTIME_INVALID,
SE_DUPE, SE_DUPE,
SE_HIGH_DIFF SE_HIGH_DIFF,
SE_INVALID_VERSION_MASK
}; };
static const char __maybe_unused *share_errs[] = { static const char __maybe_unused *share_errs[] = {
@ -285,7 +286,8 @@ static const char __maybe_unused *share_errs[] = {
"Stale", "Stale",
"Ntime out of range", "Ntime out of range",
"Duplicate", "Duplicate",
"Above target" "Above target",
"Invalid version mask"
}; };
#define SHARE_ERR(x) share_errs[((x) + 9)] #define SHARE_ERR(x) share_errs[((x) + 9)]

84
src/stratifier.c

@ -1862,7 +1862,8 @@ static void add_node_base(ckpool_t *ckp, json_t *val, bool trusted, int64_t clie
/* Calculate share diff and fill in hash and swap. Need to hold workbase read count */ /* Calculate share diff and fill in hash and swap. Need to hold workbase read count */
static double static double
share_diff(char *coinbase, const uchar *enonce1bin, const workbase_t *wb, const char *nonce2, 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) const uint32_t ntime32, const uint32_t version_mask, const char *nonce,
uchar *hash, uchar *swap, int *cblen)
{ {
unsigned char merkle_root[32], merkle_sha[64]; unsigned char merkle_root[32], merkle_sha[64];
uint32_t *data32, *swap32, benonce32; uint32_t *data32, *swap32, benonce32;
@ -1894,6 +1895,17 @@ share_diff(char *coinbase, const uchar *enonce1bin, const workbase_t *wb, const
memcpy(data, wb->headerbin, 80); memcpy(data, wb->headerbin, 80);
memcpy(data + 36, merkle_root, 32); memcpy(data + 36, merkle_root, 32);
/* Update nVersion when version_mask is in use */
if (version_mask) {
uint32_t version;
data32 = (uint32_t *)data;
version = be32toh(*data32);
version |= version_mask;
LOGDEBUG("Vmask %u version changed to %08x", version_mask, version);
*data32 = htobe32(version);
}
/* Insert the nonce value into the data */ /* Insert the nonce value into the data */
hex2bin(&benonce32, nonce, 4); hex2bin(&benonce32, nonce, 4);
data32 = (uint32_t *)(data + 64 + 12); data32 = (uint32_t *)(data + 64 + 12);
@ -1972,8 +1984,8 @@ static void send_nodes_block(sdata_t *sdata, const json_t *block_val, const int6
/* Entered with workbase readcount. */ /* Entered with workbase readcount. */
static void send_node_block(ckpool_t *ckp, sdata_t *sdata, const char *enonce1, const char *nonce, static void send_node_block(ckpool_t *ckp, sdata_t *sdata, const char *enonce1, const char *nonce,
const char *nonce2, const uint32_t ntime32, const int64_t jobid, const char *nonce2, const uint32_t ntime32, const uint32_t version_mask,
const double diff, const int64_t client_id, const int64_t jobid, const double diff, const int64_t client_id,
const char *coinbase, const int cblen, const uchar *data) const char *coinbase, const int cblen, const uchar *data)
{ {
if (sdata->node_instances) { if (sdata->node_instances) {
@ -1983,6 +1995,7 @@ static void send_node_block(ckpool_t *ckp, sdata_t *sdata, const char *enonce1,
json_set_string(val, "nonce", nonce); json_set_string(val, "nonce", nonce);
json_set_string(val, "nonce2", nonce2); json_set_string(val, "nonce2", nonce2);
json_set_uint32(val, "ntime32", ntime32); json_set_uint32(val, "ntime32", ntime32);
json_set_uint32(val, "version_mask", version_mask);
json_set_int64(val, "jobid", jobid); json_set_int64(val, "jobid", jobid);
json_set_double(val, "diff", diff); json_set_double(val, "diff", diff);
add_remote_blockdata(ckp, val, cblen, coinbase, data); add_remote_blockdata(ckp, val, cblen, coinbase, data);
@ -2110,11 +2123,11 @@ static void submit_node_block(ckpool_t *ckp, sdata_t *sdata, json_t *val)
char *coinbase = NULL, *enonce1 = NULL, *nonce = NULL, *nonce2 = NULL, *gbt_block, char *coinbase = NULL, *enonce1 = NULL, *nonce = NULL, *nonce2 = NULL, *gbt_block,
*coinbasehex, *swaphex; *coinbasehex, *swaphex;
uchar *enonce1bin = NULL, hash[32], swap[80], flip32[32]; uchar *enonce1bin = NULL, hash[32], swap[80], flip32[32];
uint32_t ntime32, version_mask = 0;
char blockhash[68], cdfield[64]; char blockhash[68], cdfield[64];
json_t *bval, *bval_copy; json_t *bval, *bval_copy;
int enonce1len, cblen; int enonce1len, cblen;
workbase_t *wb = NULL; workbase_t *wb = NULL;
uint32_t ntime32;
double diff; double diff;
ts_t ts_now; ts_t ts_now;
int64_t id; int64_t id;
@ -2145,6 +2158,11 @@ static void submit_node_block(ckpool_t *ckp, sdata_t *sdata, json_t *val)
goto out; goto out;
} }
if (!json_get_uint32(&version_mask, val, "version_mask")) {
/* No version mask is not fatal, assume it to be zero */
LOGINFO("No version mask in node method block");
}
LOGWARNING("Possible upstream block solve diff %lf !", diff); LOGWARNING("Possible upstream block solve diff %lf !", diff);
ts_realtime(&ts_now); ts_realtime(&ts_now);
@ -2176,20 +2194,21 @@ static void submit_node_block(ckpool_t *ckp, sdata_t *sdata, json_t *val)
hex2bin(enonce1bin, enonce1, enonce1len); hex2bin(enonce1bin, enonce1, enonce1len);
coinbase = alloca(wb->coinb1len + wb->enonce1constlen + wb->enonce1varlen + wb->enonce2varlen + wb->coinb2len); coinbase = alloca(wb->coinb1len + wb->enonce1constlen + wb->enonce1varlen + wb->enonce2varlen + wb->coinb2len);
/* Fill in the hashes */ /* Fill in the hashes */
share_diff(coinbase, enonce1bin, wb, nonce2, ntime32, nonce, hash, swap, &cblen); share_diff(coinbase, enonce1bin, wb, nonce2, ntime32, version_mask, nonce, hash, swap, &cblen);
} }
/* Now we have enough to assemble a block */ /* Now we have enough to assemble a block */
gbt_block = process_block(wb, coinbase, cblen, swap, hash, flip32, blockhash); gbt_block = process_block(wb, coinbase, cblen, swap, hash, flip32, blockhash);
ret = local_block_submit(ckp, gbt_block, flip32, wb->height); ret = local_block_submit(ckp, gbt_block, flip32, wb->height);
JSON_CPACK(bval, "{si,ss,ss,sI,ss,ss,ss,sI,sf,ss,ss,ss,ss}", JSON_CPACK(bval, "{si,ss,ss,sI,ss,ss,si,ss,sI,sf,ss,ss,ss,ss}",
"height", wb->height, "height", wb->height,
"blockhash", blockhash, "blockhash", blockhash,
"confirmed", "n", "confirmed", "n",
"workinfoid", wb->id, "workinfoid", wb->id,
"enonce1", enonce1, "enonce1", enonce1,
"nonce2", nonce2, "nonce2", nonce2,
"version_mask", version_mask,
"nonce", nonce, "nonce", nonce,
"reward", wb->coinbasevalue, "reward", wb->coinbasevalue,
"diff", diff, "diff", diff,
@ -5691,6 +5710,18 @@ static void stratum_send_diff(sdata_t *sdata, const stratum_instance_t *client)
stratum_add_send(sdata, json_msg, client->id, SM_DIFF); stratum_add_send(sdata, json_msg, client->id, SM_DIFF);
} }
/* Needs to be entered with client holding a ref count. */
static void stratum_send_version_mask(sdata_t *sdata, const stratum_instance_t *client)
{
char version_str[12];
json_t *json_msg;
sprintf(version_str, "%08x", client->ckp->version_mask);
JSON_CPACK(json_msg, "{s[s]soss}", "params", version_str, "id", json_null(),
"method", "mining.set_version_mask");
stratum_add_send(sdata, json_msg, client->id, SM_VERSIONMASK);
}
/* Needs to be entered with client holding a ref count. */ /* Needs to be entered with client holding a ref count. */
static void stratum_send_message(sdata_t *sdata, const stratum_instance_t *client, const char *msg) static void stratum_send_message(sdata_t *sdata, const stratum_instance_t *client, const char *msg)
{ {
@ -5864,7 +5895,8 @@ downstream_block(ckpool_t *ckp, sdata_t *sdata, const json_t *val, const int cbl
static void static void
test_blocksolve(const stratum_instance_t *client, const workbase_t *wb, const uchar *data, test_blocksolve(const stratum_instance_t *client, const workbase_t *wb, const uchar *data,
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 uint32_t ntime32, const bool stale) const char *nonce2, const char *nonce, const uint32_t ntime32, const uint32_t version_mask,
const bool stale)
{ {
char blockhash[68], cdfield[64], *gbt_block; char blockhash[68], cdfield[64], *gbt_block;
sdata_t *sdata = client->sdata; sdata_t *sdata = client->sdata;
@ -5887,8 +5919,8 @@ test_blocksolve(const stratum_instance_t *client, const workbase_t *wb, const uc
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 = process_block(wb, coinbase, cblen, data, hash, flip32, blockhash); gbt_block = process_block(wb, coinbase, cblen, data, hash, flip32, blockhash);
send_node_block(ckp, sdata, client->enonce1, nonce, nonce2, ntime32, wb->id, send_node_block(ckp, sdata, client->enonce1, nonce, nonce2, ntime32, version_mask,
diff, client->id, coinbase, cblen, data); wb->id, diff, client->id, coinbase, cblen, data);
val = json_object(); val = json_object();
json_set_int(val, "height", wb->height); json_set_int(val, "height", wb->height);
@ -5905,6 +5937,7 @@ test_blocksolve(const stratum_instance_t *client, const workbase_t *wb, const uc
json_set_string(val, "nonce2", nonce2); json_set_string(val, "nonce2", nonce2);
json_set_string(val, "nonce", nonce); json_set_string(val, "nonce", nonce);
json_set_uint32(val, "ntime32", ntime32); json_set_uint32(val, "ntime32", ntime32);
json_set_uint32(val, "version_mask", version_mask);
json_set_int64(val, "reward", wb->coinbasevalue); json_set_int64(val, "reward", wb->coinbasevalue);
json_set_double(val, "diff", diff); json_set_double(val, "diff", diff);
json_set_string(val, "createdate", cdfield); json_set_string(val, "createdate", cdfield);
@ -5934,7 +5967,8 @@ test_blocksolve(const stratum_instance_t *client, const workbase_t *wb, const uc
/* Needs to be entered with workbase readcount and client holding a ref count. */ /* Needs to be entered with workbase readcount and 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 bool stale) const uint32_t ntime32, const uint32_t version_mask,
const char *nonce, uchar *hash, const bool stale)
{ {
char *coinbase; char *coinbase;
uchar swap[80]; uchar swap[80];
@ -5944,10 +5978,10 @@ static double submission_diff(const stratum_instance_t *client, const workbase_t
coinbase = ckalloc(wb->coinb1len + wb->enonce1constlen + wb->enonce1varlen + wb->enonce2varlen + wb->coinb2len); coinbase = ckalloc(wb->coinb1len + wb->enonce1constlen + wb->enonce1varlen + wb->enonce2varlen + wb->coinb2len);
/* Calculate the diff of the share here */ /* Calculate the diff of the share here */
ret = share_diff(coinbase, client->enonce1bin, wb, nonce2, ntime32, nonce, hash, swap, &cblen); ret = share_diff(coinbase, client->enonce1bin, wb, nonce2, ntime32, version_mask, nonce, hash, swap, &cblen);
/* Test we haven't solved a block regardless of share status */ /* Test we haven't solved a block regardless of share status */
test_blocksolve(client, wb, swap, hash, ret, coinbase, cblen, nonce2, nonce, ntime32, stale); test_blocksolve(client, wb, swap, hash, ret, coinbase, cblen, nonce2, nonce, ntime32, version_mask, stale);
free(coinbase); free(coinbase);
@ -6022,17 +6056,17 @@ static json_t *parse_submit(stratum_instance_t *client, json_t *json_msg,
const json_t *params_val, json_t **err_val) const json_t *params_val, json_t **err_val)
{ {
bool share = false, result = false, invalid = true, submit = false, stale = false; bool share = false, result = false, invalid = true, submit = false, stale = false;
const char *workername, *job_id, *ntime, *nonce, *version_mask;
double diff = client->diff, wdiff = 0, sdiff = -1; double diff = client->diff, wdiff = 0, sdiff = -1;
char hexhash[68] = {}, sharehash[32], cdfield[64]; char hexhash[68] = {}, sharehash[32], cdfield[64];
const char *workername, *job_id, *ntime, *nonce;
user_instance_t *user = client->user_instance; user_instance_t *user = client->user_instance;
uint32_t ntime32, version_mask32 = 0;
char *fname = NULL, *s, *nonce2; char *fname = NULL, *s, *nonce2;
sdata_t *sdata = client->sdata; sdata_t *sdata = client->sdata;
enum share_err err = SE_NONE; enum share_err err = SE_NONE;
ckpool_t *ckp = client->ckp; ckpool_t *ckp = client->ckp;
char idstring[20] = {}; char idstring[20] = {};
workbase_t *wb = NULL; workbase_t *wb = NULL;
uint32_t ntime32;
uchar hash[32]; uchar hash[32];
int nlen, len; int nlen, len;
time_t now_t; time_t now_t;
@ -6085,6 +6119,18 @@ static json_t *parse_submit(stratum_instance_t *client, json_t *json_msg,
*err_val = JSON_ERR(err); *err_val = JSON_ERR(err);
goto out; goto out;
} }
version_mask = json_string_value(json_array_get(params_val, 5));
if (version_mask && strlen(version_mask) && validhex(version_mask)) {
sscanf(version_mask, "%x", &version_mask32);
// check version mask
if (version_mask32 && ((~ckp->version_mask) & version_mask32) != 0) {
// means client changed some bits which server doesn't allow to change
err = SE_INVALID_VERSION_MASK;
*err_val = JSON_ERR(err);
goto out;
}
}
if (safecmp(workername, client->workername)) { if (safecmp(workername, client->workername)) {
err = SE_WORKER_MISMATCH; err = SE_WORKER_MISMATCH;
*err_val = JSON_ERR(err); *err_val = JSON_ERR(err);
@ -6126,7 +6172,7 @@ static json_t *parse_submit(stratum_instance_t *client, json_t *json_msg,
} }
if (id < sdata->blockchange_id) if (id < sdata->blockchange_id)
stale = true; stale = true;
sdiff = submission_diff(client, wb, nonce2, ntime32, nonce, hash, stale); sdiff = submission_diff(client, wb, nonce2, ntime32, version_mask32, nonce, hash, stale);
if (sdiff > client->best_diff) { if (sdiff > client->best_diff) {
worker_instance_t *worker = client->worker_instance; worker_instance_t *worker = client->worker_instance;
@ -7680,13 +7726,17 @@ static void sauth_process(ckpool_t *ckp, json_params_t *jp)
mindiff = client->suggest_diff; mindiff = client->suggest_diff;
else else
mindiff = client->worker_instance->mindiff; mindiff = client->worker_instance->mindiff;
if (!mindiff) if (mindiff) {
goto out;
mindiff = MAX(ckp->mindiff, mindiff); mindiff = MAX(ckp->mindiff, mindiff);
if (mindiff != client->diff) { if (mindiff != client->diff) {
client->diff = mindiff; client->diff = mindiff;
stratum_send_diff(sdata, client); stratum_send_diff(sdata, client);
} }
}
/* Set block version mask if needed */
if (ckp->version_mask)
stratum_send_version_mask(sdata, client);
out: out:
dec_instance_ref(sdata, client); dec_instance_ref(sdata, client);
out_noclient: out_noclient:

Loading…
Cancel
Save