|
|
@ -1367,6 +1367,40 @@ static void calc_midstate(struct work *work) |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct work *make_work(void) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
struct work *work = calloc(1, sizeof(struct work)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (unlikely(!work)) |
|
|
|
|
|
|
|
quit(1, "Failed to calloc work in make_work"); |
|
|
|
|
|
|
|
mutex_lock(&control_lock); |
|
|
|
|
|
|
|
work->id = total_work++; |
|
|
|
|
|
|
|
mutex_unlock(&control_lock); |
|
|
|
|
|
|
|
return work; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This is the central place all work that is about to be retired should be
|
|
|
|
|
|
|
|
* cleaned to remove any dynamically allocated arrays within the struct */ |
|
|
|
|
|
|
|
void clean_work(struct work *work) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
free(work->job_id); |
|
|
|
|
|
|
|
free(work->nonce2); |
|
|
|
|
|
|
|
free(work->ntime); |
|
|
|
|
|
|
|
free(work->gbt_coinbase); |
|
|
|
|
|
|
|
work->job_id = NULL; |
|
|
|
|
|
|
|
work->nonce2 = NULL; |
|
|
|
|
|
|
|
work->ntime = NULL; |
|
|
|
|
|
|
|
work->gbt_coinbase = NULL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* All dynamically allocated work structs should be freed here to not leak any
|
|
|
|
|
|
|
|
* ram from arrays allocated within the work struct */ |
|
|
|
|
|
|
|
void free_work(struct work *work) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
clean_work(work); |
|
|
|
|
|
|
|
free(work); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Generate a GBT coinbase from the existing GBT variables stored. Must be
|
|
|
|
/* Generate a GBT coinbase from the existing GBT variables stored. Must be
|
|
|
|
* entered under gbt_lock */ |
|
|
|
* entered under gbt_lock */ |
|
|
|
static void __build_gbt_coinbase(struct pool *pool) |
|
|
|
static void __build_gbt_coinbase(struct pool *pool) |
|
|
@ -1477,10 +1511,52 @@ static unsigned char *__gbt_merkleroot(struct pool *pool) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void calc_diff(struct work *work, int known); |
|
|
|
static void calc_diff(struct work *work, int known); |
|
|
|
|
|
|
|
static bool work_decode(struct pool *pool, struct work *work, json_t *val); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void update_gbt(struct pool *pool) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
int rolltime; |
|
|
|
|
|
|
|
json_t *val; |
|
|
|
|
|
|
|
CURL *curl; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
curl = curl_easy_init(); |
|
|
|
|
|
|
|
if (unlikely(!curl)) |
|
|
|
|
|
|
|
quit (1, "CURL initialisation failed in update_gbt"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val = json_rpc_call(curl, pool->rpc_url, pool->rpc_userpass, |
|
|
|
|
|
|
|
pool->rpc_req, true, false, &rolltime, pool, false); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (val) { |
|
|
|
|
|
|
|
struct work *work = make_work(); |
|
|
|
|
|
|
|
bool rc = work_decode(pool, work, val); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
total_getworks++; |
|
|
|
|
|
|
|
pool->getwork_requested++; |
|
|
|
|
|
|
|
if (rc) { |
|
|
|
|
|
|
|
applog(LOG_DEBUG, "Successfully retrieved and updated GBT from pool %u %s", |
|
|
|
|
|
|
|
pool->pool_no, pool->rpc_url); |
|
|
|
|
|
|
|
gettimeofday(&pool->tv_idle, NULL); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
applog(LOG_DEBUG, "Successfully retrieved but FAILED to decipher GBT from pool %u %s", |
|
|
|
|
|
|
|
pool->pool_no, pool->rpc_url); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
json_decref(val); |
|
|
|
|
|
|
|
free_work(work); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
applog(LOG_DEBUG, "FAILED to update GBT from pool %u %s", |
|
|
|
|
|
|
|
pool->pool_no, pool->rpc_url); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
curl_easy_cleanup(curl); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void gen_gbt_work(struct pool *pool, struct work *work) |
|
|
|
static void gen_gbt_work(struct pool *pool, struct work *work) |
|
|
|
{ |
|
|
|
{ |
|
|
|
unsigned char *merkleroot; |
|
|
|
unsigned char *merkleroot; |
|
|
|
|
|
|
|
struct timeval now; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gettimeofday(&now, NULL); |
|
|
|
|
|
|
|
if (now.tv_sec - pool->tv_lastwork.tv_sec > 60) |
|
|
|
|
|
|
|
update_gbt(pool); |
|
|
|
|
|
|
|
|
|
|
|
mutex_lock(&pool->gbt_lock); |
|
|
|
mutex_lock(&pool->gbt_lock); |
|
|
|
__build_gbt_coinbase(pool); |
|
|
|
__build_gbt_coinbase(pool); |
|
|
@ -2646,40 +2722,6 @@ static bool get_upstream_work(struct work *work, CURL *curl) |
|
|
|
return rc; |
|
|
|
return rc; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static struct work *make_work(void) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
struct work *work = calloc(1, sizeof(struct work)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (unlikely(!work)) |
|
|
|
|
|
|
|
quit(1, "Failed to calloc work in make_work"); |
|
|
|
|
|
|
|
mutex_lock(&control_lock); |
|
|
|
|
|
|
|
work->id = total_work++; |
|
|
|
|
|
|
|
mutex_unlock(&control_lock); |
|
|
|
|
|
|
|
return work; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This is the central place all work that is about to be retired should be
|
|
|
|
|
|
|
|
* cleaned to remove any dynamically allocated arrays within the struct */ |
|
|
|
|
|
|
|
void clean_work(struct work *work) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
free(work->job_id); |
|
|
|
|
|
|
|
free(work->nonce2); |
|
|
|
|
|
|
|
free(work->ntime); |
|
|
|
|
|
|
|
free(work->gbt_coinbase); |
|
|
|
|
|
|
|
work->job_id = NULL; |
|
|
|
|
|
|
|
work->nonce2 = NULL; |
|
|
|
|
|
|
|
work->ntime = NULL; |
|
|
|
|
|
|
|
work->gbt_coinbase = NULL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* All dynamically allocated work structs should be freed here to not leak any
|
|
|
|
|
|
|
|
* ram from arrays allocated within the work struct */ |
|
|
|
|
|
|
|
void free_work(struct work *work) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
clean_work(work); |
|
|
|
|
|
|
|
free(work); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void workio_cmd_free(struct workio_cmd *wc) |
|
|
|
static void workio_cmd_free(struct workio_cmd *wc) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (!wc) |
|
|
|
if (!wc) |
|
|
@ -5785,7 +5827,7 @@ static struct pool *select_longpoll_pool(struct pool *cp) |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
static void wait_lpcurrent(struct pool *pool) |
|
|
|
static void wait_lpcurrent(struct pool *pool) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (pool->enabled == POOL_REJECTING || pool_strategy == POOL_LOADBALANCE || pool_strategy == POOL_BALANCE) |
|
|
|
if (cnx_needed(pool)) |
|
|
|
return; |
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
while (pool != current_pool() && pool_strategy != POOL_LOADBALANCE && pool_strategy != POOL_BALANCE) { |
|
|
|
while (pool != current_pool() && pool_strategy != POOL_LOADBALANCE && pool_strategy != POOL_BALANCE) { |
|
|
@ -5953,48 +5995,6 @@ static void reap_curl(struct pool *pool) |
|
|
|
applog(LOG_DEBUG, "Reaped %d curl%s from pool %d", reaped, reaped > 1 ? "s" : "", pool->pool_no); |
|
|
|
applog(LOG_DEBUG, "Reaped %d curl%s from pool %d", reaped, reaped > 1 ? "s" : "", pool->pool_no); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool pool_getswork(struct pool *pool) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
bool ret = false; |
|
|
|
|
|
|
|
int rolltime; |
|
|
|
|
|
|
|
json_t *val; |
|
|
|
|
|
|
|
CURL *curl; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
curl = curl_easy_init(); |
|
|
|
|
|
|
|
if (unlikely(!curl)) |
|
|
|
|
|
|
|
quit (1, "CURL initialisation failed in pool_getswork"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val = json_rpc_call(curl, pool->rpc_url, pool->rpc_userpass, |
|
|
|
|
|
|
|
pool->rpc_req, true, false, &rolltime, pool, false); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (val) { |
|
|
|
|
|
|
|
struct work *work = make_work(); |
|
|
|
|
|
|
|
bool rc = work_decode(pool, work, val); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (pool->has_gbt && pool == current_pool()) { |
|
|
|
|
|
|
|
total_getworks++; |
|
|
|
|
|
|
|
pool->getwork_requested++; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (rc) { |
|
|
|
|
|
|
|
applog(LOG_DEBUG, "Successfully retrieved and deciphered work from pool %u %s", |
|
|
|
|
|
|
|
pool->pool_no, pool->rpc_url); |
|
|
|
|
|
|
|
gettimeofday(&pool->tv_idle, NULL); |
|
|
|
|
|
|
|
ret = true; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
applog(LOG_DEBUG, "Successfully retrieved but FAILED to decipher work from pool %u %s", |
|
|
|
|
|
|
|
pool->pool_no, pool->rpc_url); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
json_decref(val); |
|
|
|
|
|
|
|
free_work(work); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
applog(LOG_DEBUG, "FAILED to retrieve pool_getswork work from pool %u %s", |
|
|
|
|
|
|
|
pool->pool_no, pool->rpc_url); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
curl_easy_cleanup(curl); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ret; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void *watchpool_thread(void __maybe_unused *userdata) |
|
|
|
static void *watchpool_thread(void __maybe_unused *userdata) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int intervals = 0; |
|
|
|
int intervals = 0; |
|
|
@ -6020,16 +6020,6 @@ static void *watchpool_thread(void __maybe_unused *userdata) |
|
|
|
if (pool->enabled == POOL_DISABLED || pool->has_stratum) |
|
|
|
if (pool->enabled == POOL_DISABLED || pool->has_stratum) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
/* Stratum works off pushing work, but GBT and getwork
|
|
|
|
|
|
|
|
* off requests so even for the non current pool, get |
|
|
|
|
|
|
|
* new work once per minute to ensure the pool is still |
|
|
|
|
|
|
|
* alive and to maintain the current block template for |
|
|
|
|
|
|
|
* GBT pools in case we switch to them. */ |
|
|
|
|
|
|
|
if (!pool->idle && now.tv_sec - pool->tv_lastwork.tv_sec > 60) { |
|
|
|
|
|
|
|
if (!pool_getswork(pool)) |
|
|
|
|
|
|
|
pool_died(pool); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Test pool is idle once every minute */ |
|
|
|
/* Test pool is idle once every minute */ |
|
|
|
if (pool->idle && now.tv_sec - pool->tv_idle.tv_sec > 30) { |
|
|
|
if (pool->idle && now.tv_sec - pool->tv_idle.tv_sec > 30) { |
|
|
|
gettimeofday(&pool->tv_idle, NULL); |
|
|
|
gettimeofday(&pool->tv_idle, NULL); |
|
|
|