Browse Source

Merge commit '9484dc1' into bfgminer

Luke Dashjr 12 years ago
parent
commit
d30eb6d040
4 changed files with 158 additions and 126 deletions
  1. 41 53
      miner.c
  2. 11 15
      miner.h
  3. 43 58
      util.c
  4. 63 0
      util.h

+ 41 - 53
miner.c

@@ -1914,8 +1914,7 @@ static struct work *make_work(void)
 void clean_work(struct work *work)
 {
 	free(work->job_id);
-	free(work->nonce2);
-	free(work->ntime);
+	bytes_free(&work->nonce2);
 	free(work->nonce1);
 
 	if (work->tmpl) {
@@ -1940,7 +1939,7 @@ void free_work(struct work *work)
 	free(work);
 }
 
-static char *workpadding = "000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000";
+static const char *workpadding_bin = "\0\0\0\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x80\x02\0\0";
 
 // Must only be called with ch_lock held!
 static
@@ -2071,7 +2070,7 @@ static bool work_decode(struct pool *pool, struct work *work, json_t *val)
 		if (blkmk_get_data(work->tmpl, work->data, 80, time(NULL), NULL, &work->dataid) < 76)
 			return false;
 		swap32yes(work->data, work->data, 80 / 4);
-		memcpy(&work->data[80], "\0\0\0\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x80\x02\0\0", 48);
+		memcpy(&work->data[80], workpadding_bin, 48);
 
 		const struct blktmpl_longpoll_req *lp;
 		if ((lp = blktmpl_get_longpoll(work->tmpl)) && ((!pool->lp_id) || strcmp(lp->id, pool->lp_id))) {
@@ -3918,10 +3917,7 @@ void __copy_work(struct work *work, const struct work *base_work)
 		work->job_id = strdup(base_work->job_id);
 	if (base_work->nonce1)
 		work->nonce1 = strdup(base_work->nonce1);
-	if (base_work->nonce2)
-		work->nonce2 = strdup(base_work->nonce2);
-	if (base_work->ntime)
-		work->ntime = strdup(base_work->ntime);
+	bytes_cpy(&work->nonce2, &base_work->nonce2);
 
 	if (base_work->tmpl) {
 		struct pool *pool = work->pool;
@@ -4445,12 +4441,16 @@ next_write_sws_del:
 			struct stratum_share *sshare = calloc(sizeof(struct stratum_share), 1);
 			int sshare_id;
 			uint32_t nonce;
+			char *nonce2hex;
 			char *noncehex;
+			char *ntimehex;
 			
 			sshare->sshare_time = time(NULL);
 			sshare->work = copy_work(work);
+			nonce2hex = bin2hex(bytes_buf(&work->nonce2), bytes_len(&work->nonce2));
 			nonce = *((uint32_t *)(work->data + 76));
 			noncehex = bin2hex((const unsigned char *)&nonce, 4);
+			ntimehex = bin2hex((void *)&work->data[68], 4);
 			
 			mutex_lock(&sshare_lock);
 			/* Give the stratum share a unique id */
@@ -4458,10 +4458,12 @@ next_write_sws_del:
 			sshare->id = swork_id++;
 			HASH_ADD_INT(stratum_shares, id, sshare);
 			sprintf(s, "{\"params\": [\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"], \"id\": %d, \"method\": \"mining.submit\"}",
-				pool->rpc_user, work->job_id, work->nonce2, work->ntime, noncehex, sshare->id);
+				pool->rpc_user, work->job_id, nonce2hex, ntimehex, noncehex, sshare->id);
 			mutex_unlock(&sshare_lock);
 			
+			free(nonce2hex);
 			free(noncehex);
+			free(ntimehex);
 			
 			applog(LOG_DEBUG, "DBG: sending %s submit RPC call: %s", pool->stratum_url, s);
 
@@ -6756,14 +6758,14 @@ static void *stratum_thread(void *userdata)
 			gen_stratum_work(pool, work);
 
 			/* Try to extract block height from coinbase scriptSig */
-			char *hex_height = &pool->swork.coinbase1[8 /*version*/ + 2 /*txin count*/ + 72 /*prevout*/ + 2 /*scriptSig len*/ + 2 /*push opcode*/];
+			uint8_t *bin_height = &bytes_buf(&pool->swork.coinbase)[4 /*version*/ + 1 /*txin count*/ + 36 /*prevout*/ + 1 /*scriptSig len*/ + 1 /*push opcode*/];
 			unsigned char cb_height_sz;
-			hex2bin(&cb_height_sz, &hex_height[-2], 1);
+			cb_height_sz = bin_height[-1];
 			if (cb_height_sz == 3) {
 				// FIXME: The block number will overflow this by AD 2173
 				uint32_t block_id = ((uint32_t*)work->data)[1];
 				uint32_t height = 0;
-				hex2bin((unsigned char*)&height, hex_height, 3);
+				memcpy(&height, bin_height, 3);
 				height = le32toh(height);
 				have_block_height(block_id, height);
 			}
@@ -7148,10 +7150,11 @@ void set_target(unsigned char *dest_target, double diff)
 static void gen_stratum_work(struct pool *pool, struct work *work)
 {
 	unsigned char *coinbase, merkle_root[32], merkle_sha[64];
-	char *header, *merkle_hash;
+	uint8_t *merkle_bin;
 	uint32_t *data32, *swap32;
-	size_t alloc_len;
 	int i;
+	
+	coinbase = bytes_buf(&pool->swork.coinbase);
 
 	clean_work(work);
 
@@ -7159,29 +7162,20 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
 	cg_ilock(&pool->data_lock);
 
 	/* Generate coinbase */
-	work->nonce2 = bin2hex((const unsigned char *)&pool->nonce2, pool->n2size);
+	// FIXME: This only works if (n2size == 4) || (n2size < 4 && littleendian)
+	bytes_resize(&work->nonce2, pool->n2size);
+	memcpy(bytes_buf(&work->nonce2), &pool->nonce2, pool->n2size);
+	memcpy(&coinbase[pool->swork.nonce2_offset], &pool->nonce2, pool->n2size);
 	pool->nonce2++;
 
 	/* Downgrade to a read lock to read off the pool variables */
 	cg_dlock(&pool->data_lock);
-	alloc_len = pool->swork.cb_len;
-	align_len(&alloc_len);
-	coinbase = calloc(alloc_len, 1);
-	if (unlikely(!coinbase))
-		quit(1, "Failed to calloc coinbase in gen_stratum_work");
-	hex2bin(coinbase, pool->swork.coinbase1, pool->swork.cb1_len);
-	hex2bin(coinbase + pool->swork.cb1_len, pool->nonce1, pool->n1_len);
-	hex2bin(coinbase + pool->swork.cb1_len + pool->n1_len, work->nonce2, pool->n2size);
-	hex2bin(coinbase + pool->swork.cb1_len + pool->n1_len + pool->n2size, pool->swork.coinbase2, pool->swork.cb2_len);
 
 	/* Generate merkle root */
-	gen_hash(coinbase, merkle_root, pool->swork.cb_len);
-	free(coinbase);
+	gen_hash(coinbase, merkle_root, bytes_len(&pool->swork.coinbase));
 	memcpy(merkle_sha, merkle_root, 32);
-	for (i = 0; i < pool->swork.merkles; i++) {
-		unsigned char merkle_bin[32];
-
-		hex2bin(merkle_bin, pool->swork.merkle[i], 32);
+	merkle_bin = bytes_buf(&pool->swork.merkle_bin);
+	for (i = 0; i < pool->swork.merkles; ++i, merkle_bin += 32) {
 		memcpy(merkle_sha + 32, merkle_bin, 32);
 		gen_hash(merkle_sha, merkle_root, 64);
 		memcpy(merkle_sha, merkle_root, 32);
@@ -7189,19 +7183,14 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
 	data32 = (uint32_t *)merkle_sha;
 	swap32 = (uint32_t *)merkle_root;
 	flip32(swap32, data32);
-	merkle_hash = bin2hex((const unsigned char *)merkle_root, 32);
-
-	header = calloc(pool->swork.header_len, 1);
-	if (unlikely(!header))
-		quit(1, "Failed to calloc header in gen_stratum_work");
-	sprintf(header, "%s%s%s%s%s%s%s",
-		pool->swork.bbversion,
-		pool->swork.prev_hash,
-		merkle_hash,
-		pool->swork.ntime,
-		pool->swork.nbit,
-		"00000000", /* nonce */
-		workpadding);
+	
+	memcpy(&work->data[0], pool->swork.header1, 36);
+	memcpy(&work->data[36], merkle_root, 32);
+	*((uint32_t*)&work->data[68]) = 0; // FIXME: big endian time
+	memcpy(&work->data[68], pool->swork.ntime, 4);
+	memcpy(&work->data[72], pool->swork.diffbits, 4);
+	memset(&work->data[76], 0, 4);  // nonce
+	memcpy(&work->data[80], workpadding_bin, 48);
 
 	/* Store the stratum work diff to check it still matches the pool's
 	 * stratum diff when submitting shares */
@@ -7210,19 +7199,18 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
 	/* Copy parameters required for share submission */
 	work->job_id = strdup(pool->swork.job_id);
 	work->nonce1 = strdup(pool->nonce1);
-	work->ntime = strdup(pool->swork.ntime);
 	cg_runlock(&pool->data_lock);
 
-	applog(LOG_DEBUG, "Generated stratum merkle %s", merkle_hash);
-	applog(LOG_DEBUG, "Generated stratum header %s", header);
-	applog(LOG_DEBUG, "Work job_id %s nonce2 %s ntime %s", work->job_id, work->nonce2, work->ntime);
-
-	free(merkle_hash);
+	if (opt_debug)
+	{
+		char *header = bin2hex(work->data, 80);
+		char *nonce2hex = bin2hex(bytes_buf(&work->nonce2), bytes_len(&work->nonce2));
+		applog(LOG_DEBUG, "Generated stratum header %s", header);
+		applog(LOG_DEBUG, "Work job_id %s nonce2 %s", work->job_id, nonce2hex);
+		free(header);
+		free(nonce2hex);
+	}
 
-	/* Convert hex data to binary data for work */
-	if (unlikely(!hex2bin(work->data, header, 128)))
-		quit(1, "Failed to convert header to data in gen_stratum_work");
-	free(header);
 	calc_midstate(work);
 
 	set_target(work->target, work->sdiff);

+ 11 - 15
miner.h

@@ -1062,21 +1062,18 @@ enum pool_protocol {
 
 struct stratum_work {
 	char *job_id;
-	char *prev_hash;
-	char *coinbase1;
-	char *coinbase2;
-	char **merkle;
-	char *bbversion;
-	char *nbit;
-	char *ntime;
 	bool clean;
-
-	size_t cb1_len;
-	size_t cb2_len;
-	size_t cb_len;
-
-	size_t header_len;
+	
+	bytes_t coinbase;
+	size_t nonce2_offset;
+	
 	int merkles;
+	bytes_t merkle_bin;
+	
+	uint8_t header1[36];
+	uint8_t diffbits[4];
+	uint8_t ntime[4];
+
 	double diff;
 
 	bool transparency_probed;
@@ -1221,8 +1218,7 @@ struct work {
 
 	bool		stratum;
 	char 		*job_id;
-	char		*nonce2;
-	char		*ntime;
+	bytes_t		nonce2;
 	double		sdiff;
 	char		*nonce1;
 

+ 43 - 58
util.c

@@ -1523,6 +1523,7 @@ static bool parse_notify(struct pool *pool, json_t *val)
 	char *job_id, *prev_hash, *coinbase1, *coinbase2, *bbversion, *nbit, *ntime;
 	bool clean, ret = false;
 	int merkles, i;
+	size_t cb1_len, cb2_len;
 	json_t *arr;
 
 	arr = json_array_get(val, 4);
@@ -1530,86 +1531,65 @@ static bool parse_notify(struct pool *pool, json_t *val)
 		goto out;
 
 	merkles = json_array_size(arr);
+	for (i = 0; i < merkles; i++)
+		if (!json_is_string(json_array_get(arr, i)))
+			goto out;
 
-	job_id = json_array_string(val, 0);
-	prev_hash = json_array_string(val, 1);
-	coinbase1 = json_array_string(val, 2);
-	coinbase2 = json_array_string(val, 3);
-	bbversion = json_array_string(val, 5);
-	nbit = json_array_string(val, 6);
-	ntime = json_array_string(val, 7);
+	prev_hash = __json_array_string(val, 1);
+	coinbase1 = __json_array_string(val, 2);
+	coinbase2 = __json_array_string(val, 3);
+	bbversion = __json_array_string(val, 5);
+	nbit = __json_array_string(val, 6);
+	ntime = __json_array_string(val, 7);
 	clean = json_is_true(json_array_get(val, 8));
 
-	if (!job_id || !prev_hash || !coinbase1 || !coinbase2 || !bbversion || !nbit || !ntime) {
-		/* Annoying but we must not leak memory */
-		if (job_id)
-			free(job_id);
-		if (prev_hash)
-			free(prev_hash);
-		if (coinbase1)
-			free(coinbase1);
-		if (coinbase2)
-			free(coinbase2);
-		if (bbversion)
-			free(bbversion);
-		if (nbit)
-			free(nbit);
-		if (ntime)
-			free(ntime);
+	if (!prev_hash || !coinbase1 || !coinbase2 || !bbversion || !nbit || !ntime)
+		goto out;
+	
+	job_id = json_array_string(val, 0);
+	if (!job_id)
 		goto out;
-	}
 
 	cg_wlock(&pool->data_lock);
 	free(pool->swork.job_id);
-	free(pool->swork.prev_hash);
-	free(pool->swork.coinbase1);
-	free(pool->swork.coinbase2);
-	free(pool->swork.bbversion);
-	free(pool->swork.nbit);
-	free(pool->swork.ntime);
 	pool->swork.job_id = job_id;
-	pool->swork.prev_hash = prev_hash;
-	pool->swork.coinbase1 = coinbase1;
-	pool->swork.cb1_len = strlen(coinbase1) / 2;
-	pool->swork.coinbase2 = coinbase2;
-	pool->swork.cb2_len = strlen(coinbase2) / 2;
-	pool->swork.bbversion = bbversion;
-	pool->swork.nbit = nbit;
-	pool->swork.ntime = ntime;
 	pool->submit_old = !clean;
 	pool->swork.clean = true;
-	pool->swork.cb_len = pool->swork.cb1_len + pool->n1_len + pool->n2size + pool->swork.cb2_len;
-
-	for (i = 0; i < pool->swork.merkles; i++)
-		free(pool->swork.merkle[i]);
-	if (merkles) {
-		pool->swork.merkle = realloc(pool->swork.merkle, sizeof(char *) * merkles + 1);
-		for (i = 0; i < merkles; i++)
-			pool->swork.merkle[i] = json_array_string(arr, i);
-	}
+	
+	hex2bin(&pool->swork.header1[0], bbversion,  4);
+	hex2bin(&pool->swork.header1[4], prev_hash, 32);
+	hex2bin(&pool->swork.ntime[0], ntime, 4);
+	hex2bin(&pool->swork.diffbits[0], nbit, 4);
+	
+	cb1_len = strlen(coinbase1) / 2;
+	pool->swork.nonce2_offset = cb1_len + pool->n1_len;
+	cb2_len = strlen(coinbase2) / 2;
+
+	bytes_resize(&pool->swork.coinbase, pool->swork.nonce2_offset + pool->n2size + cb2_len);
+	uint8_t *coinbase = bytes_buf(&pool->swork.coinbase);
+	hex2bin(coinbase, coinbase1, cb1_len);
+	hex2bin(&coinbase[cb1_len], pool->nonce1, pool->n1_len);
+	// NOTE: gap for nonce2, filled at work generation time
+	hex2bin(&coinbase[pool->swork.nonce2_offset + pool->n2size], coinbase2, cb2_len);
+	
+	bytes_resize(&pool->swork.merkle_bin, 32 * merkles);
+	for (i = 0; i < merkles; i++)
+		hex2bin(&bytes_buf(&pool->swork.merkle_bin)[i * 32], json_string_value(json_array_get(arr, i)), 32);
 	pool->swork.merkles = merkles;
 	if (clean)
 		pool->nonce2 = 0;
-	pool->swork.header_len = strlen(pool->swork.bbversion) +
-				 strlen(pool->swork.prev_hash) +
-				 strlen(pool->swork.ntime) +
-				 strlen(pool->swork.nbit) +
-	/* merkle_hash */	 32 +
-	/* nonce */		 8 +
-	/* workpadding */	 96;
-	pool->swork.header_len = pool->swork.header_len * 2 + 1;
-	align_len(&pool->swork.header_len);
 	cg_wunlock(&pool->data_lock);
 
 	applog(LOG_DEBUG, "Received stratum notify from pool %u with job_id=%s",
 	       pool->pool_no, job_id);
-	if (opt_protocol) {
+	if (opt_debug && opt_protocol)
+	{
 		applog(LOG_DEBUG, "job_id: %s", job_id);
 		applog(LOG_DEBUG, "prev_hash: %s", prev_hash);
 		applog(LOG_DEBUG, "coinbase1: %s", coinbase1);
 		applog(LOG_DEBUG, "coinbase2: %s", coinbase2);
 		for (i = 0; i < merkles; i++)
-			applog(LOG_DEBUG, "merkle%d: %s", i, pool->swork.merkle[i]);
+			applog(LOG_DEBUG, "merkle%d: %s", i, json_string_value(json_array_get(arr, i)));
 		applog(LOG_DEBUG, "bbversion: %s", bbversion);
 		applog(LOG_DEBUG, "nbit: %s", nbit);
 		applog(LOG_DEBUG, "ntime: %s", ntime);
@@ -2469,3 +2449,8 @@ void notifier_destroy(notifier_t fd)
 #endif
 	fd[0] = fd[1] = INVSOCK;
 }
+
+void _bytes_alloc_failure(size_t sz)
+{
+	quit(1, "bytes_resize failed to allocate %lu bytes", (unsigned long)sz);
+}

+ 63 - 0
util.h

@@ -133,6 +133,69 @@ static inline void align_len(size_t *len)
 }
 
 
+typedef struct bytes_t {
+	uint8_t *buf;
+	size_t sz;
+	size_t allocsz;
+} bytes_t;
+
+// This can't be inline without ugly const/non-const issues
+#define bytes_buf(b)  ((b)->buf)
+
+static inline
+size_t bytes_len(const bytes_t *b)
+{
+	return b->sz;
+}
+
+extern void _bytes_alloc_failure(size_t);
+
+static inline
+void bytes_resize(bytes_t *b, size_t newsz)
+{
+	b->sz = newsz;
+	if (newsz <= b->allocsz)
+		return;
+	
+	if (!b->allocsz)
+		b->allocsz = 0x10;
+	do {
+		b->allocsz *= 2;
+	} while (newsz > b->allocsz);
+	b->buf = realloc(b->buf, b->allocsz);
+	if (!b->buf)
+		_bytes_alloc_failure(b->allocsz);
+}
+
+static inline
+void bytes_cat(bytes_t *b, const bytes_t *cat)
+{
+	size_t origsz = bytes_len(b);
+	size_t addsz = bytes_len(cat);
+	bytes_resize(b, origsz + addsz);
+	memcpy(&bytes_buf(b)[origsz], bytes_buf(cat), addsz);
+}
+
+static inline
+void bytes_cpy(bytes_t *dst, const bytes_t *src)
+{
+	dst->allocsz = src->allocsz;
+	dst->sz = src->sz;
+	size_t half;
+	while (dst->sz <= (half = dst->allocsz / 2))
+		dst->allocsz = half;
+	dst->buf = malloc(dst->allocsz);
+	memcpy(dst->buf, src->buf, dst->sz);
+}
+
+static inline
+void bytes_free(bytes_t *b)
+{
+	free(b->buf);
+	b->sz = b->allocsz = 0;
+}
+
+
 static inline
 void set_maxfd(int *p_maxfd, int fd)
 {