|
|
@@ -239,7 +239,7 @@ int swork_id;
|
|
|
struct stratum_share {
|
|
|
UT_hash_handle hh;
|
|
|
bool block;
|
|
|
- struct work work;
|
|
|
+ struct work *work;
|
|
|
int id;
|
|
|
};
|
|
|
|
|
|
@@ -1469,9 +1469,7 @@ static void calc_diff(struct work *work, int known);
|
|
|
static void gen_gbt_work(struct pool *pool, struct work *work)
|
|
|
{
|
|
|
unsigned char *merkleroot;
|
|
|
- char *cbhex;
|
|
|
|
|
|
- memset(work->job_id, 0, 64);
|
|
|
mutex_lock(&pool->gbt_lock);
|
|
|
__build_gbt_coinbase(pool);
|
|
|
merkleroot = __gbt_merkleroot(pool);
|
|
|
@@ -1483,15 +1481,13 @@ static void gen_gbt_work(struct pool *pool, struct work *work)
|
|
|
|
|
|
memcpy(work->target, pool->gbt_target, 32);
|
|
|
|
|
|
- cbhex = bin2hex(pool->gbt_coinbase, pool->coinbase_len);
|
|
|
- sprintf(work->gbt_coinbase, "%s", cbhex);
|
|
|
- free(cbhex);
|
|
|
+ work->gbt_coinbase = bin2hex(pool->gbt_coinbase, pool->coinbase_len);
|
|
|
|
|
|
/* For encoding the block data on submission */
|
|
|
work->gbt_txns = pool->gbt_txns + 1;
|
|
|
|
|
|
if (pool->gbt_workid)
|
|
|
- sprintf(work->job_id, "%s", pool->gbt_workid);
|
|
|
+ work->job_id = strdup(pool->gbt_workid);
|
|
|
mutex_unlock(&pool->gbt_lock);
|
|
|
|
|
|
memcpy(work->data + 4 + 32, merkleroot, 32);
|
|
|
@@ -2307,7 +2303,7 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit)
|
|
|
|
|
|
/* build JSON-RPC request */
|
|
|
if (work->gbt) {
|
|
|
- char gbt_block[1024], *varint, *header;
|
|
|
+ char gbt_block[4096], *varint, *header;
|
|
|
unsigned char data[80];
|
|
|
|
|
|
flip80(data, work->data);
|
|
|
@@ -2334,7 +2330,7 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit)
|
|
|
free(varint);
|
|
|
strcat(gbt_block, work->gbt_coinbase);
|
|
|
|
|
|
- if (strlen(work->job_id))
|
|
|
+ if (work->job_id)
|
|
|
sprintf(s, "{\"id\": 0, \"method\": \"submitblock\", \"params\": [\"%s\", {\"workid\": \"%s\"}]}", gbt_block, work->job_id);
|
|
|
else
|
|
|
sprintf(s, "{\"id\": 0, \"method\": \"submitblock\", \"params\": [\"%s\", {}]}", gbt_block);
|
|
|
@@ -2634,8 +2630,25 @@ static struct work *make_work(void)
|
|
|
return work;
|
|
|
}
|
|
|
|
|
|
-static void free_work(struct work *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);
|
|
|
}
|
|
|
|
|
|
@@ -2948,11 +2961,37 @@ static void roll_work(struct work *work)
|
|
|
work->id = total_work++;
|
|
|
}
|
|
|
|
|
|
+/* Duplicates any dynamically allocated arrays within the work struct to
|
|
|
+ * prevent a copied work struct from freeing ram belonging to another struct */
|
|
|
+void __copy_work(struct work *work, struct work *base_work)
|
|
|
+{
|
|
|
+ clean_work(work);
|
|
|
+ memcpy(work, base_work, sizeof(struct work));
|
|
|
+ if (work->job_id)
|
|
|
+ work->job_id = strdup(base_work->job_id);
|
|
|
+ if (work->nonce2)
|
|
|
+ work->nonce2 = strdup(base_work->nonce2);
|
|
|
+ if (work->ntime)
|
|
|
+ work->ntime = strdup(base_work->ntime);
|
|
|
+ if (work->gbt_coinbase)
|
|
|
+ work->gbt_coinbase = strdup(base_work->gbt_coinbase);
|
|
|
+}
|
|
|
+
|
|
|
+/* Generates a copy of an existing work struct, creating fresh heap allocations
|
|
|
+ * for all dynamically allocated arrays within the struct */
|
|
|
+struct work *copy_work(struct work *base_work)
|
|
|
+{
|
|
|
+ struct work *work = make_work();
|
|
|
+
|
|
|
+ __copy_work(work, base_work);
|
|
|
+
|
|
|
+ return work;
|
|
|
+}
|
|
|
+
|
|
|
static struct work *make_clone(struct work *work)
|
|
|
{
|
|
|
- struct work *work_clone = make_work();
|
|
|
+ struct work *work_clone = copy_work(work);
|
|
|
|
|
|
- memcpy(work_clone, work, sizeof(struct work));
|
|
|
work_clone->clone = true;
|
|
|
gettimeofday((struct timeval *)&(work_clone->tv_cloned), NULL);
|
|
|
work_clone->longpoll = false;
|
|
|
@@ -3016,7 +3055,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work);
|
|
|
static void *get_work_thread(void *userdata)
|
|
|
{
|
|
|
struct workio_cmd *wc = (struct workio_cmd *)userdata;
|
|
|
- struct work *ret_work= NULL;
|
|
|
+ struct work *ret_work = NULL;
|
|
|
struct curl_ent *ce = NULL;
|
|
|
struct pool *pool;
|
|
|
|
|
|
@@ -3232,7 +3271,7 @@ static void *submit_work_thread(void *userdata)
|
|
|
char *noncehex;
|
|
|
char s[1024];
|
|
|
|
|
|
- memcpy(&sshare->work, work, sizeof(struct work));
|
|
|
+ sshare->work = copy_work(work);
|
|
|
mutex_lock(&sshare_lock);
|
|
|
/* Give the stratum share a unique id */
|
|
|
sshare->id = swork_id++;
|
|
|
@@ -4538,7 +4577,7 @@ out_unlock:
|
|
|
static void stratum_share_result(json_t *val, json_t *res_val, json_t *err_val,
|
|
|
struct stratum_share *sshare)
|
|
|
{
|
|
|
- struct work *work = &sshare->work;
|
|
|
+ struct work *work = sshare->work;
|
|
|
uint64_t sharediff = share_diff(work);
|
|
|
char hashshow[65];
|
|
|
uint32_t *hash32;
|
|
|
@@ -4602,6 +4641,7 @@ static bool parse_stratum_response(struct pool *pool, char *s)
|
|
|
goto out;
|
|
|
}
|
|
|
stratum_share_result(val, res_val, err_val, sshare);
|
|
|
+ free_work(sshare->work);
|
|
|
free(sshare);
|
|
|
|
|
|
ret = true;
|
|
|
@@ -4621,8 +4661,9 @@ static void clear_stratum_shares(struct pool *pool)
|
|
|
|
|
|
mutex_lock(&sshare_lock);
|
|
|
HASH_ITER(hh, stratum_shares, sshare, tmpshare) {
|
|
|
- if (sshare->work.pool == pool) {
|
|
|
+ if (sshare->work->pool == pool) {
|
|
|
HASH_DEL(stratum_shares, sshare);
|
|
|
+ free_work(sshare->work);
|
|
|
free(sshare);
|
|
|
cleared++;
|
|
|
}
|
|
|
@@ -5129,17 +5170,13 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
|
|
|
{
|
|
|
unsigned char *coinbase, merkle_root[32], merkle_sha[64], *merkle_hash;
|
|
|
int len, cb1_len, n1_len, cb2_len, i;
|
|
|
- char header[260], *nonce2;
|
|
|
uint32_t *data32, *swap32;
|
|
|
-
|
|
|
- memset(work->job_id, 0, 64);
|
|
|
- memset(work->nonce2, 0, 64);
|
|
|
- memset(work->ntime, 0, 16);
|
|
|
+ char header[260];
|
|
|
|
|
|
mutex_lock(&pool->pool_lock);
|
|
|
|
|
|
/* Generate coinbase */
|
|
|
- nonce2 = bin2hex((const unsigned char *)&pool->nonce2, pool->n2size);
|
|
|
+ work->nonce2 = bin2hex((const unsigned char *)&pool->nonce2, pool->n2size);
|
|
|
pool->nonce2++;
|
|
|
cb1_len = strlen(pool->swork.coinbase1) / 2;
|
|
|
n1_len = strlen(pool->nonce1) / 2;
|
|
|
@@ -5148,7 +5185,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
|
|
|
coinbase = alloca(len + 1);
|
|
|
hex2bin(coinbase, pool->swork.coinbase1, cb1_len);
|
|
|
hex2bin(coinbase + cb1_len, pool->nonce1, n1_len);
|
|
|
- hex2bin(coinbase + cb1_len + n1_len, nonce2, pool->n2size);
|
|
|
+ hex2bin(coinbase + cb1_len + n1_len, work->nonce2, pool->n2size);
|
|
|
hex2bin(coinbase + cb1_len + n1_len + pool->n2size, pool->swork.coinbase2, cb2_len);
|
|
|
|
|
|
/* Generate merkle root */
|
|
|
@@ -5181,10 +5218,8 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
|
|
|
work->sdiff = pool->swork.diff;
|
|
|
|
|
|
/* Copy parameters required for share submission */
|
|
|
- sprintf(work->job_id, "%s", pool->swork.job_id);
|
|
|
- sprintf(work->nonce2, "%s", nonce2);
|
|
|
- sprintf(work->ntime, "%s", pool->swork.ntime);
|
|
|
- free(nonce2);
|
|
|
+ work->job_id = strdup(pool->swork.job_id);
|
|
|
+ work->ntime = strdup(pool->swork.ntime);
|
|
|
|
|
|
mutex_unlock(&pool->pool_lock);
|
|
|
|
|
|
@@ -5225,6 +5260,8 @@ static void get_work(struct work *work, struct thr_info *thr, const int thr_id)
|
|
|
* should not be restarted */
|
|
|
thread_reportout(thr);
|
|
|
|
|
|
+ clean_work(work);
|
|
|
+
|
|
|
if (opt_benchmark) {
|
|
|
get_benchmark_work(work);
|
|
|
goto out;
|
|
|
@@ -5298,7 +5335,7 @@ retry:
|
|
|
pool_resus(pool);
|
|
|
}
|
|
|
|
|
|
- memcpy(work, work_heap, sizeof(struct work));
|
|
|
+ __copy_work(work, work_heap);
|
|
|
free_work(work_heap);
|
|
|
|
|
|
out:
|
|
|
@@ -5307,7 +5344,7 @@ out:
|
|
|
work->mined = true;
|
|
|
}
|
|
|
|
|
|
-bool submit_work_sync(struct thr_info *thr, const struct work *work_in, struct timeval *tv_work_found)
|
|
|
+bool submit_work_sync(struct thr_info *thr, struct work *work_in, struct timeval *tv_work_found)
|
|
|
{
|
|
|
struct workio_cmd *wc;
|
|
|
|
|
|
@@ -5318,10 +5355,9 @@ bool submit_work_sync(struct thr_info *thr, const struct work *work_in, struct t
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- wc->work = make_work();
|
|
|
+ wc->work = copy_work(work_in);
|
|
|
wc->cmd = WC_SUBMIT_WORK;
|
|
|
wc->thr = thr;
|
|
|
- memcpy(wc->work, work_in, sizeof(*work_in));
|
|
|
if (tv_work_found)
|
|
|
memcpy(&(wc->work->tv_work_found), tv_work_found, sizeof(struct timeval));
|
|
|
|