Browse Source

Merge branch 'stratum_target' into bfgminer

Conflicts:
	miner.c
Luke Dashjr 11 years ago
parent
commit
c59d9804c0
3 changed files with 140 additions and 47 deletions
  1. 115 41
      miner.c
  2. 4 3
      miner.h
  3. 21 3
      util.c

+ 115 - 41
miner.c

@@ -1221,7 +1221,7 @@ char *set_quit_summary(const char * const arg)
 	return NULL;
 }
 
-static void bdiff_target_leadzero(unsigned char *target, double diff);
+static void pdiff_target_leadzero(void *, double);
 
 char *set_request_diff(const char *arg, float *p)
 {
@@ -1231,7 +1231,7 @@ char *set_request_diff(const char *arg, float *p)
 		return e;
 	
 	request_bdiff = (double)*p * 0.9999847412109375;
-	bdiff_target_leadzero(target, request_bdiff);
+	pdiff_target_leadzero(target, *p);
 	request_target_str = malloc(65);
 	bin2hex(request_target_str, target, 32);
 	
@@ -4763,7 +4763,7 @@ void get_benchmark_work(struct work *work)
 	memcpy(&work->data[ 0], blkhdr, 80);
 	memcpy(&work->data[80], workpadding_bin, 48);
 	calc_midstate(work);
-	set_target(work->target, 1.0);
+	set_target_to_pdiff(work->target, 1.0);
 	
 	work->mandatory = true;
 	work->pool = pools[0];
@@ -8049,7 +8049,7 @@ fishy:
 		/* Since the share is untracked, we can only guess at what the
 		 * work difficulty is based on the current pool diff. */
 		cg_rlock(&pool->data_lock);
-		pool_diff = pool->swork.diff;
+		pool_diff = target_diff(pool->swork.target);
 		cg_runlock(&pool->data_lock);
 
 		if (json_is_true(res_val)) {
@@ -8783,42 +8783,33 @@ void gen_hash(unsigned char *data, unsigned char *hash, int len)
 	sha256(hash1, 32, hash);
 }
 
-/* Diff 1 is a 256 bit unsigned integer of
- * 0x00000000ffff0000000000000000000000000000000000000000000000000000
- * so we use a big endian 64 bit unsigned integer centred on the 5th byte to
+/* PDiff 1 is a 256 bit unsigned integer of
+ * 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ * so we use a big endian 32 bit unsigned integer positioned at the Nth byte to
  * cover a huge range of difficulty targets, though not all 256 bits' worth */
-static void bdiff_target_leadzero(unsigned char *target, double diff)
-{
-	uint64_t *data64, h64;
-	double d64;
-
-	d64 = diffone;
-	d64 /= diff;
-	d64 = ceil(d64);
-	h64 = d64;
-
-	memset(target, 0, 32);
-	if (d64 < 18446744073709551616.0) {
-		unsigned char *rtarget = target;
-		memset(rtarget, 0, 32);
-		if (opt_scrypt)
-			data64 = (uint64_t *)(rtarget + 2);
-		else
-			data64 = (uint64_t *)(rtarget + 4);
-		*data64 = htobe64(h64);
-	} else {
-		/* Support for the classic all FFs just-below-1 diff */
-		if (opt_scrypt)
-			memset(&target[2], 0xff, 30);
-		else
-			memset(&target[4], 0xff, 28);
+static void pdiff_target_leadzero(void * const target_p, double diff)
+{
+	uint8_t *target = target_p;
+	diff *= 0x100000000;
+	int skip = log2(diff) / 8;
+	if (skip)
+	{
+		if (skip > 0x1c)
+			skip = 0x1c;
+		diff /= pow(0x100, skip);
+		memset(target, 0, skip);
 	}
+	uint32_t n = 0xffffffff;
+	n = (double)n / diff;
+	n = htobe32(n);
+	memcpy(&target[skip], &n, sizeof(n));
+	memset(&target[skip + sizeof(n)], 0xff, 32 - (skip + sizeof(n)));
 }
 
-void set_target(unsigned char *dest_target, double diff)
+void set_target_to_pdiff(void * const dest_target, const double pdiff)
 {
 	unsigned char rtarget[32];
-	bdiff_target_leadzero(rtarget, diff);
+	pdiff_target_leadzero(rtarget, pdiff);
 	swab256(dest_target, rtarget);
 	
 	if (opt_debug) {
@@ -8828,6 +8819,77 @@ void set_target(unsigned char *dest_target, double diff)
 	}
 }
 
+void set_target_to_bdiff(void * const dest_target, const double bdiff)
+{
+	set_target_to_pdiff(dest_target, bdiff_to_pdiff(bdiff));
+}
+
+void _test_target(void * const funcp, const char * const funcname, const bool little_endian, const void * const expectp, const double diff)
+{
+	uint8_t bufr[32], buf[32], expectr[32], expect[32];
+	int off;
+	void (*func)(void *, double) = funcp;
+	
+	func(little_endian ? bufr : buf, diff);
+	if (little_endian)
+		swab256(buf, bufr);
+	
+	swap32tobe(expect, expectp, 256/32);
+	
+	// Fuzzy comparison: the first 32 bits set must match, and the actual target must be >= the expected
+	for (off = 0; off < 28 && !buf[off]; ++off)
+	{}
+	
+	if (memcmp(&buf[off], &expect[off], 4))
+	{
+testfail: ;
+		char hexbuf[65], expectbuf[65];
+		bin2hex(hexbuf, buf, 32);
+		bin2hex(expectbuf, expect, 32);
+		applogr(, LOG_WARNING, "%s test failed: diff %g got %s (expected %s)",
+		        funcname, diff, hexbuf, expectbuf);
+	}
+	
+	if (!little_endian)
+		swab256(bufr, buf);
+	swab256(expectr, expect);
+	
+	if (!hash_target_check(expectr, bufr))
+		goto testfail;
+}
+
+#define TEST_TARGET(func, le, expect, diff)  \
+	_test_target(func, #func, le, expect, diff)
+
+void test_target()
+{
+	uint32_t expect[8] = {0};
+	// bdiff 1 should be exactly 00000000ffff0000000006f29cfd29510a6caee84634e86a57257cf03152537f due to floating-point imprecision (pdiff1 / 1.0000152590218966)
+	expect[0] = 0x0000ffff;
+	TEST_TARGET(set_target_to_bdiff, true, expect, 1./0x10000);
+	expect[0] = 0;
+	expect[1] = 0xffff0000;
+	TEST_TARGET(set_target_to_bdiff, true, expect, 1);
+	expect[1] >>= 1;
+	TEST_TARGET(set_target_to_bdiff, true, expect, 2);
+	expect[1] >>= 3;
+	TEST_TARGET(set_target_to_bdiff, true, expect, 0x10);
+	expect[1] >>= 4;
+	TEST_TARGET(set_target_to_bdiff, true, expect, 0x100);
+	
+	memset(&expect[1], '\xff', 28);
+	expect[0] = 0x0000ffff;
+	TEST_TARGET(set_target_to_pdiff, true, expect, 1./0x10000);
+	expect[0] = 0;
+	TEST_TARGET(set_target_to_pdiff, true, expect, 1);
+	expect[1] >>= 1;
+	TEST_TARGET(set_target_to_pdiff, true, expect, 2);
+	expect[1] >>= 3;
+	TEST_TARGET(set_target_to_pdiff, true, expect, 0x10);
+	expect[1] >>= 4;
+	TEST_TARGET(set_target_to_pdiff, true, expect, 0x100);
+}
+
 void stratum_work_cpy(struct stratum_work * const dst, const struct stratum_work * const src)
 {
 	*dst = *src;
@@ -8908,11 +8970,8 @@ void gen_stratum_work2(struct work *work, struct stratum_work *swork, const char
 	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 */
-	work->sdiff = swork->diff;
-
 	/* Copy parameters required for share submission */
+	memcpy(work->target, swork->target, sizeof(work->target));
 	work->job_id = strdup(swork->job_id);
 	work->nonce1 = strdup(nonce1);
 	if (swork->data_lock_p)
@@ -8930,8 +8989,6 @@ void gen_stratum_work2(struct work *work, struct stratum_work *swork, const char
 
 	calc_midstate(work);
 
-	set_target(work->target, work->sdiff);
-
 	local_work++;
 	work->stratum = true;
 	work->blk.nonce = 0;
@@ -9108,7 +9165,23 @@ enum test_nonce2_result hashtest2(struct work *work, bool checktarget)
 		return TNR_GOOD;
 
 	if (!hash_target_check_v(work->hash, work->target))
-		return TNR_HIGH;
+	{
+		bool high_hash = true;
+		struct pool * const pool = work->pool;
+		if (pool->stratum_active)
+		{
+			// Some stratum pools are buggy and expect difficulty changes to be immediate retroactively, so if the target has changed, check and submit just in case
+			if (memcmp(pool->swork.target, work->target, sizeof(work->target)))
+			{
+				applog(LOG_DEBUG, "Stratum pool %u target has changed since work job issued, checking that too",
+				       pool->pool_no);
+				if (hash_target_check_v(work->hash, pool->swork.target))
+					high_hash = false;
+			}
+		}
+		if (high_hash)
+			return TNR_HIGH;
+	}
 
 	return TNR_GOOD;
 }
@@ -11703,6 +11776,7 @@ int main(int argc, char *argv[])
 		test_intrange();
 		test_decimal_width();
 		test_domain_funcs();
+		test_target();
 		utf8_test();
 	}
 

+ 4 - 3
miner.h

@@ -1001,7 +1001,9 @@ extern void clear_stratum_shares(struct pool *pool);
 extern void hashmeter2(struct thr_info *);
 extern bool stale_work(struct work *, bool share);
 extern bool stale_work_future(struct work *, bool share, unsigned long ustime);
-extern void set_target(unsigned char *dest_target, double diff);
+extern void set_target_to_pdiff(void *dest_target, double pdiff);
+#define bdiff_to_pdiff(n) (n * 1.0000152587)
+extern void set_target_to_bdiff(void *dest_target, double bdiff);
 
 extern void kill_work(void);
 extern void app_restart(void);
@@ -1145,7 +1147,7 @@ struct stratum_work {
 	uint32_t ntime;
 	struct timeval tv_received;
 
-	double diff;
+	uint8_t target[32];
 
 	bool transparency_probed;
 	struct timeval tv_transparency;
@@ -1305,7 +1307,6 @@ struct work {
 	bool		stratum;
 	char 		*job_id;
 	bytes_t		nonce2;
-	double		sdiff;
 	char		*nonce1;
 
 	unsigned char	work_restart_id;

+ 21 - 3
util.c

@@ -2163,11 +2163,29 @@ static bool parse_diff(struct pool *pool, json_t *val)
 	if (diff == 0)
 		return false;
 
+	if ((int64_t)diff != diff)
+	{
+		// Always assume fractional values are proper bdiff per specification
+		diff = bdiff_to_pdiff(diff);
+	}
+	else
+	{
+		// Integer; allow it to be interpreted as pdiff, since some the difference is trivial and some pools see it this way
+		if (opt_scrypt)
+		{
+			// Some scrypt pools multiply difficulty by 0x10000; since diff 1 is pretty difficult for scrypt right now, this is a safe assumption (otherwise they would be using a fractional value)
+			diff /= 0x10000;
+		}
+	}
+	
+	if ((!opt_scrypt) && diff < 1 && diff > 0.999)
+		diff = 1;
+	
 	cg_wlock(&pool->data_lock);
-	pool->swork.diff = diff;
+	set_target_to_pdiff(pool->swork.target, diff);
 	cg_wunlock(&pool->data_lock);
 
-	applog(LOG_DEBUG, "Pool %d stratum bdifficulty set to %f", pool->pool_no, diff);
+	applog(LOG_DEBUG, "Pool %d stratum difficulty set to %g", pool->pool_no, diff);
 
 	return true;
 }
@@ -2673,7 +2691,7 @@ out:
 		if (!pool->stratum_url)
 			pool->stratum_url = pool->sockaddr_url;
 		pool->stratum_active = true;
-		pool->swork.diff = 1;
+		set_target_to_pdiff(pool->swork.target, 1);
 		if (opt_protocol) {
 			applog(LOG_DEBUG, "Pool %d confirmed mining.subscribe with extranonce1 %s extran2size %d",
 			       pool->pool_no, pool->nonce1, pool->n2size);