|
|
@ -236,6 +236,9 @@ struct stratum_instance { |
|
|
|
* or other problem and should be dropped lazily if |
|
|
|
* or other problem and should be dropped lazily if |
|
|
|
* this is set to 2 */ |
|
|
|
* this is set to 2 */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool vmask; /* Requested vmask */ |
|
|
|
|
|
|
|
uint32_t version_mask; /* Mask to use for this client */ |
|
|
|
|
|
|
|
|
|
|
|
int latency; /* Latency when on a mining node */ |
|
|
|
int latency; /* Latency when on a mining node */ |
|
|
|
|
|
|
|
|
|
|
|
bool reconnect; /* This client really needs to reconnect */ |
|
|
|
bool reconnect; /* This client really needs to reconnect */ |
|
|
@ -309,6 +312,8 @@ struct proxy_base { |
|
|
|
bool subscribed; |
|
|
|
bool subscribed; |
|
|
|
bool notified; |
|
|
|
bool notified; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t version_mask; |
|
|
|
|
|
|
|
|
|
|
|
int64_t clients; /* Incrementing client count */ |
|
|
|
int64_t clients; /* Incrementing client count */ |
|
|
|
int64_t max_clients; /* Maximum number of clients per subproxy */ |
|
|
|
int64_t max_clients; /* Maximum number of clients per subproxy */ |
|
|
|
int64_t bound_clients; /* Currently actively bound clients */ |
|
|
|
int64_t bound_clients; /* Currently actively bound clients */ |
|
|
@ -1864,7 +1869,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, 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; |
|
|
@ -1896,6 +1902,13 @@ 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) { |
|
|
|
|
|
|
|
version_mask = htobe32(version_mask); |
|
|
|
|
|
|
|
data32 = (uint32_t *)data; |
|
|
|
|
|
|
|
*data32 |= version_mask; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* 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); |
|
|
@ -1974,8 +1987,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) { |
|
|
@ -1985,6 +1998,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); |
|
|
@ -2112,11 +2126,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; |
|
|
@ -2147,6 +2161,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); |
|
|
@ -2178,20 +2197,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, |
|
|
@ -2626,6 +2646,11 @@ static void reconnect_global_clients(sdata_t *sdata) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
if (!client->authorised) |
|
|
|
if (!client->authorised) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
|
|
|
|
/* Does the client mandate a vmask but the best proxy not
|
|
|
|
|
|
|
|
* support it? Not ideal because there may be a better priority |
|
|
|
|
|
|
|
* pool below the best priority one that does support it. */ |
|
|
|
|
|
|
|
if (client->vmask && !proxy->version_mask) |
|
|
|
|
|
|
|
continue; |
|
|
|
/* Is this client bound to a dead proxy? */ |
|
|
|
/* Is this client bound to a dead proxy? */ |
|
|
|
if (!client->reconnect) { |
|
|
|
if (!client->reconnect) { |
|
|
|
/* This client is bound to a user proxy */ |
|
|
|
/* This client is bound to a user proxy */ |
|
|
@ -2873,31 +2898,6 @@ static void update_subscribe(ckpool_t *ckp, const char *cmd) |
|
|
|
check_proxy(sdata, proxy); |
|
|
|
check_proxy(sdata, proxy); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Find the highest priority alive proxy belonging to userid and recruit extra
|
|
|
|
|
|
|
|
* subproxies. */ |
|
|
|
|
|
|
|
static void recruit_best_userproxy(sdata_t *sdata, const int userid, const int recruits) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
proxy_t *proxy, *subproxy, *tmp, *subtmp; |
|
|
|
|
|
|
|
int id = -1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mutex_lock(&sdata->proxy_lock); |
|
|
|
|
|
|
|
HASH_ITER(hh, sdata->proxies, proxy, tmp) { |
|
|
|
|
|
|
|
if (proxy->userid < userid) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
if (proxy->userid > userid) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
HASH_ITER(sh, proxy->subproxies, subproxy, subtmp) { |
|
|
|
|
|
|
|
if (subproxy->dead) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
id = proxy->id; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
mutex_unlock(&sdata->proxy_lock); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (id != -1) |
|
|
|
|
|
|
|
generator_recruit(sdata->ckp, id, recruits); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Check how much headroom the userid proxies have and reconnect any clients
|
|
|
|
/* Check how much headroom the userid proxies have and reconnect any clients
|
|
|
|
* that are not bound to it that should be */ |
|
|
|
* that are not bound to it that should be */ |
|
|
|
static void check_userproxies(sdata_t *sdata, proxy_t *proxy, const int userid) |
|
|
|
static void check_userproxies(sdata_t *sdata, proxy_t *proxy, const int userid) |
|
|
@ -2919,6 +2919,10 @@ static void check_userproxies(sdata_t *sdata, proxy_t *proxy, const int userid) |
|
|
|
if (client->proxy->userid == userid && |
|
|
|
if (client->proxy->userid == userid && |
|
|
|
client->proxy->parent->priority <= proxy->parent->priority) |
|
|
|
client->proxy->parent->priority <= proxy->parent->priority) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
|
|
|
|
/* Tested proxy doesn't have vmask support while client
|
|
|
|
|
|
|
|
* mandates it. */ |
|
|
|
|
|
|
|
if (client->vmask && !proxy->version_mask) |
|
|
|
|
|
|
|
continue; |
|
|
|
if (headroom-- < 1) |
|
|
|
if (headroom-- < 1) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
reconnects++; |
|
|
|
reconnects++; |
|
|
@ -2927,11 +2931,11 @@ static void check_userproxies(sdata_t *sdata, proxy_t *proxy, const int userid) |
|
|
|
ck_runlock(&sdata->instance_lock); |
|
|
|
ck_runlock(&sdata->instance_lock); |
|
|
|
|
|
|
|
|
|
|
|
if (reconnects) { |
|
|
|
if (reconnects) { |
|
|
|
LOGINFO("%d clients flagged for reconnect to user %d proxies", |
|
|
|
LOGINFO("%d clients flagged for reconnect to user %d proxy %d", |
|
|
|
reconnects, userid); |
|
|
|
reconnects, userid, proxy->id); |
|
|
|
} |
|
|
|
} |
|
|
|
if (headroom < 0) |
|
|
|
if (headroom < 0) |
|
|
|
recruit_best_userproxy(sdata, userid, -headroom); |
|
|
|
generator_recruit(sdata->ckp, proxy->id, -headroom); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void update_notify(ckpool_t *ckp, const char *cmd) |
|
|
|
static void update_notify(ckpool_t *ckp, const char *cmd) |
|
|
@ -3032,6 +3036,15 @@ out: |
|
|
|
json_decref(val); |
|
|
|
json_decref(val); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void stratum_set_proxy_vmask(ckpool_t *ckp, int id, int subid, uint32_t version_mask) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
proxy_t *proxy; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proxy = existing_subproxy(ckp->sdata, id, subid); |
|
|
|
|
|
|
|
proxy->version_mask = version_mask; |
|
|
|
|
|
|
|
LOGINFO("Stratum Proxy %d:%d had version mask set to %08x", id, subid, version_mask); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void stratum_send_diff(sdata_t *sdata, const stratum_instance_t *client); |
|
|
|
static void stratum_send_diff(sdata_t *sdata, const stratum_instance_t *client); |
|
|
|
|
|
|
|
|
|
|
|
static void update_diff(ckpool_t *ckp, const char *cmd) |
|
|
|
static void update_diff(ckpool_t *ckp, const char *cmd) |
|
|
@ -4720,7 +4733,7 @@ static bool new_enonce1(ckpool_t *ckp, sdata_t *ckp_sdata, sdata_t *sdata, strat |
|
|
|
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); |
|
|
|
|
|
|
|
|
|
|
|
/* Need to hold sdata->proxy_lock */ |
|
|
|
/* Need to hold sdata->proxy_lock */ |
|
|
|
static proxy_t *__best_subproxy(proxy_t *proxy) |
|
|
|
static proxy_t *__best_subproxy(proxy_t *proxy, const bool vmask) |
|
|
|
{ |
|
|
|
{ |
|
|
|
proxy_t *subproxy, *best = NULL, *tmp; |
|
|
|
proxy_t *subproxy, *best = NULL, *tmp; |
|
|
|
int64_t max_headroom; |
|
|
|
int64_t max_headroom; |
|
|
@ -4733,6 +4746,8 @@ static proxy_t *__best_subproxy(proxy_t *proxy) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
if (!subproxy->sdata->current_workbase) |
|
|
|
if (!subproxy->sdata->current_workbase) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
|
|
|
|
if (vmask && !subproxy->version_mask) |
|
|
|
|
|
|
|
continue; |
|
|
|
/* This subproxy data is checked without holding the correct
|
|
|
|
/* This subproxy data is checked without holding the correct
|
|
|
|
* instance_lock but an incorrect value here is harmless */ |
|
|
|
* instance_lock but an incorrect value here is harmless */ |
|
|
|
subproxy_headroom = subproxy->max_clients - subproxy->clients - subproxy->connecting; |
|
|
|
subproxy_headroom = subproxy->max_clients - subproxy->clients - subproxy->connecting; |
|
|
@ -4751,8 +4766,9 @@ static proxy_t *__best_subproxy(proxy_t *proxy) |
|
|
|
/* Choose the stratifier data for a new client. Use the main ckp_sdata except
|
|
|
|
/* Choose the stratifier data for a new client. Use the main ckp_sdata except
|
|
|
|
* in proxy mode where we find a subproxy based on the current proxy with room |
|
|
|
* in proxy mode where we find a subproxy based on the current proxy with room |
|
|
|
* for more clients. Signal the generator to recruit more subproxies if we are |
|
|
|
* for more clients. Signal the generator to recruit more subproxies if we are |
|
|
|
* running out of room. */ |
|
|
|
* running out of room. Needs to be entered with client holding a ref count */ |
|
|
|
static sdata_t *select_sdata(ckpool_t *ckp, sdata_t *ckp_sdata, const int userid) |
|
|
|
static sdata_t *select_sdata(ckpool_t *ckp, sdata_t *ckp_sdata, const bool vmask, |
|
|
|
|
|
|
|
const int userid) |
|
|
|
{ |
|
|
|
{ |
|
|
|
proxy_t *global, *proxy, *tmp, *best = NULL; |
|
|
|
proxy_t *global, *proxy, *tmp, *best = NULL; |
|
|
|
|
|
|
|
|
|
|
@ -4762,14 +4778,18 @@ static sdata_t *select_sdata(ckpool_t *ckp, sdata_t *ckp_sdata, const int userid |
|
|
|
/* Proxies are ordered by priority so first available will be the best
|
|
|
|
/* Proxies are ordered by priority so first available will be the best
|
|
|
|
* priority */ |
|
|
|
* priority */ |
|
|
|
mutex_lock(&ckp_sdata->proxy_lock); |
|
|
|
mutex_lock(&ckp_sdata->proxy_lock); |
|
|
|
best = global = ckp_sdata->proxy; |
|
|
|
global = ckp_sdata->proxy; |
|
|
|
|
|
|
|
/* If the client needs a version mask, only use sdata from pools with
|
|
|
|
|
|
|
|
* one set. */ |
|
|
|
|
|
|
|
if (!vmask || ckp->version_mask) |
|
|
|
|
|
|
|
best = global; |
|
|
|
|
|
|
|
|
|
|
|
HASH_ITER(hh, ckp_sdata->proxies, proxy, tmp) { |
|
|
|
HASH_ITER(hh, ckp_sdata->proxies, proxy, tmp) { |
|
|
|
if (proxy->userid < userid) |
|
|
|
if (proxy->userid < userid) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
if (proxy->userid > userid) |
|
|
|
if (proxy->userid > userid) |
|
|
|
break; |
|
|
|
break; |
|
|
|
best = __best_subproxy(proxy); |
|
|
|
best = __best_subproxy(proxy, vmask); |
|
|
|
if (best) |
|
|
|
if (best) |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
@ -4881,7 +4901,7 @@ static json_t *parse_subscribe(stratum_instance_t *client, const int64_t client_ |
|
|
|
return json_string("params not an array"); |
|
|
|
return json_string("params not an array"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
sdata = select_sdata(ckp, ckp_sdata, 0); |
|
|
|
sdata = select_sdata(ckp, ckp_sdata, client->vmask, 0); |
|
|
|
if (unlikely(!ckp->node && (!sdata || !sdata->current_workbase))) { |
|
|
|
if (unlikely(!ckp->node && (!sdata || !sdata->current_workbase))) { |
|
|
|
LOGWARNING("Failed to provide subscription due to no %s", sdata ? "current workbase" : "sdata"); |
|
|
|
LOGWARNING("Failed to provide subscription due to no %s", sdata ? "current workbase" : "sdata"); |
|
|
|
stratum_send_message(ckp_sdata, client, "Pool Initialising"); |
|
|
|
stratum_send_message(ckp_sdata, client, "Pool Initialising"); |
|
|
@ -4936,7 +4956,7 @@ static json_t *parse_subscribe(stratum_instance_t *client, const int64_t client_ |
|
|
|
if (userid == -1) |
|
|
|
if (userid == -1) |
|
|
|
userid = userid_from_sessionip(ckp_sdata, client->address); |
|
|
|
userid = userid_from_sessionip(ckp_sdata, client->address); |
|
|
|
if (userid != -1) { |
|
|
|
if (userid != -1) { |
|
|
|
sdata_t *user_sdata = select_sdata(ckp, ckp_sdata, userid); |
|
|
|
sdata_t *user_sdata = select_sdata(ckp, ckp_sdata, client->vmask, userid); |
|
|
|
|
|
|
|
|
|
|
|
if (user_sdata) |
|
|
|
if (user_sdata) |
|
|
|
sdata = user_sdata; |
|
|
|
sdata = user_sdata; |
|
|
@ -5866,7 +5886,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; |
|
|
@ -5889,8 +5910,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); |
|
|
@ -5907,6 +5928,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); |
|
|
@ -5936,7 +5958,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]; |
|
|
@ -5946,10 +5969,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); |
|
|
|
|
|
|
|
|
|
|
@ -5984,7 +6007,7 @@ static void update_client(const stratum_instance_t *client, const int64_t client |
|
|
|
/* Submit a share in proxy mode to the parent pool. workbase_lock is held.
|
|
|
|
/* Submit a share in proxy mode to the parent pool. workbase_lock is held.
|
|
|
|
* Needs to be entered with client holding a ref count. */ |
|
|
|
* Needs to be entered with client holding a ref count. */ |
|
|
|
static void submit_share(stratum_instance_t *client, const int64_t jobid, const char *nonce2, |
|
|
|
static void submit_share(stratum_instance_t *client, const int64_t jobid, const char *nonce2, |
|
|
|
const char *ntime, const char *nonce) |
|
|
|
const char *ntime, const char *nonce, const char *version_mask) |
|
|
|
{ |
|
|
|
{ |
|
|
|
ckpool_t *ckp = client->ckp; |
|
|
|
ckpool_t *ckp = client->ckp; |
|
|
|
json_t *json_msg; |
|
|
|
json_t *json_msg; |
|
|
@ -5994,6 +6017,8 @@ static void submit_share(stratum_instance_t *client, const int64_t jobid, const |
|
|
|
JSON_CPACK(json_msg, "{sIsssssssIsIsi}", "jobid", jobid, "nonce2", enonce2, |
|
|
|
JSON_CPACK(json_msg, "{sIsssssssIsIsi}", "jobid", jobid, "nonce2", enonce2, |
|
|
|
"ntime", ntime, "nonce", nonce, "client_id", client->id, |
|
|
|
"ntime", ntime, "nonce", nonce, "client_id", client->id, |
|
|
|
"proxy", client->proxyid, "subproxy", client->subproxyid); |
|
|
|
"proxy", client->proxyid, "subproxy", client->subproxyid); |
|
|
|
|
|
|
|
if (version_mask) |
|
|
|
|
|
|
|
json_set_string(json_msg, "vmask", version_mask); |
|
|
|
generator_add_send(ckp, json_msg); |
|
|
|
generator_add_send(ckp, json_msg); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -6024,17 +6049,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; |
|
|
@ -6087,6 +6112,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 && ((~client->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); |
|
|
@ -6128,7 +6165,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; |
|
|
|
|
|
|
|
|
|
|
@ -6207,7 +6244,7 @@ out_nowb: |
|
|
|
* stale shares and filter out the rest. */ |
|
|
|
* stale shares and filter out the rest. */ |
|
|
|
if (wb && wb->proxy && submit) { |
|
|
|
if (wb && wb->proxy && submit) { |
|
|
|
LOGINFO("Submitting share upstream: %s", hexhash); |
|
|
|
LOGINFO("Submitting share upstream: %s", hexhash); |
|
|
|
submit_share(client, id, nonce2, ntime, nonce); |
|
|
|
submit_share(client, id, nonce2, ntime, nonce, version_mask); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
add_submit(ckp, client, diff, result, submit); |
|
|
|
add_submit(ckp, client, diff, result, submit); |
|
|
@ -6431,11 +6468,30 @@ static void suggest_diff(ckpool_t *ckp, stratum_instance_t *client, const char * |
|
|
|
stratum_send_diff(ckp->sdata, client); |
|
|
|
stratum_send_diff(ckp->sdata, client); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Needs to be entered with client holding a ref count */ |
|
|
|
|
|
|
|
static void stratum_send_version_mask(sdata_t *sdata, stratum_instance_t *client) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
char version_str[12]; |
|
|
|
|
|
|
|
json_t *json_msg; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (unlikely(!client->proxy)) { |
|
|
|
|
|
|
|
LOGERR("stratum_send_version_mask called on a non proxied client"); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
client->version_mask = client->proxy->version_mask; |
|
|
|
|
|
|
|
sprintf(version_str, "%08x", client->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); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Send diff first when sending the first stratum template after subscribing */ |
|
|
|
/* Send diff first when sending the first stratum template after subscribing */ |
|
|
|
static void init_client(const stratum_instance_t *client, const int64_t client_id) |
|
|
|
static void init_client(ckpool_t *ckp, stratum_instance_t *client, const int64_t client_id) |
|
|
|
{ |
|
|
|
{ |
|
|
|
sdata_t *sdata = client->sdata; |
|
|
|
sdata_t *sdata = client->sdata; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ckp->proxy && client->vmask) |
|
|
|
|
|
|
|
stratum_send_version_mask(client->sdata, client); |
|
|
|
stratum_send_diff(sdata, client); |
|
|
|
stratum_send_diff(sdata, client); |
|
|
|
stratum_send_update(sdata, client_id, true); |
|
|
|
stratum_send_update(sdata, client_id, true); |
|
|
|
} |
|
|
|
} |
|
|
@ -6561,7 +6617,7 @@ static void parse_method(ckpool_t *ckp, sdata_t *sdata, stratum_instance_t *clie |
|
|
|
json_object_set_new_nocheck(val, "error", json_null()); |
|
|
|
json_object_set_new_nocheck(val, "error", json_null()); |
|
|
|
stratum_add_send(sdata, val, client_id, SM_SUBSCRIBERESULT); |
|
|
|
stratum_add_send(sdata, val, client_id, SM_SUBSCRIBERESULT); |
|
|
|
if (likely(client->subscribed)) |
|
|
|
if (likely(client->subscribed)) |
|
|
|
init_client(client, client_id); |
|
|
|
init_client(ckp, client, client_id); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -6638,6 +6694,27 @@ static void parse_method(ckpool_t *ckp, sdata_t *sdata, stratum_instance_t *clie |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (cmdmatch(method, "mining.configure")) { |
|
|
|
|
|
|
|
json_t *val, *result_val; |
|
|
|
|
|
|
|
char version_str[12]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LOGINFO("Mining configure requested from %s %s", client->identity, |
|
|
|
|
|
|
|
client->address); |
|
|
|
|
|
|
|
client->vmask = true; |
|
|
|
|
|
|
|
/* Send a temporary vmask in proxy mode till we know what the
|
|
|
|
|
|
|
|
* real vmask will be for the upstream pool. */ |
|
|
|
|
|
|
|
sprintf(version_str, "%08x", ckp->version_mask); |
|
|
|
|
|
|
|
client->version_mask = ckp->version_mask; |
|
|
|
|
|
|
|
val = json_object(); |
|
|
|
|
|
|
|
JSON_CPACK(result_val, "{sbss}", "version-rolling", json_true(), |
|
|
|
|
|
|
|
"version-rolling.mask", version_str); |
|
|
|
|
|
|
|
json_object_set_new_nocheck(val, "result", result_val); |
|
|
|
|
|
|
|
json_object_set_nocheck(val, "id", id_val); |
|
|
|
|
|
|
|
json_object_set_new_nocheck(val, "error", json_null()); |
|
|
|
|
|
|
|
stratum_add_send(sdata, val, client_id, SM_CONFIGURE); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* We should only accept requests from subscribed and authed users here
|
|
|
|
/* We should only accept requests from subscribed and authed users here
|
|
|
|
* on */ |
|
|
|
* on */ |
|
|
|
if (!client->subscribed) { |
|
|
|
if (!client->subscribed) { |
|
|
@ -7682,13 +7759,14 @@ 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); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
out: |
|
|
|
out: |
|
|
|
dec_instance_ref(sdata, client); |
|
|
|
dec_instance_ref(sdata, client); |
|
|
|
out_noclient: |
|
|
|
out_noclient: |
|
|
|