Browse Source

Merge branch 'work2d' into bfgminer

Conflicts:
	miner.c
Luke Dashjr 11 years ago
parent
commit
870ecf7a0f
8 changed files with 127 additions and 69 deletions
  1. 1 1
      Makefile.am
  2. 5 0
      configure.ac
  3. 14 49
      driver-stratum.c
  4. 17 9
      miner.c
  5. 8 3
      miner.h
  6. 7 7
      util.c
  7. 70 0
      work2d.c
  8. 5 0
      work2d.h

+ 1 - 1
Makefile.am

@@ -202,7 +202,7 @@ if NEED_DYNCLOCK
 bfgminer_SOURCES += dynclock.c dynclock.h
 bfgminer_SOURCES += dynclock.c dynclock.h
 endif
 endif
 
 
-if USE_LIBEVENT
+if NEED_BFG_WORK2D
 bfgminer_SOURCES  += work2d.c work2d.h
 bfgminer_SOURCES  += work2d.c work2d.h
 endif
 endif
 
 

+ 5 - 0
configure.ac

@@ -130,6 +130,7 @@ need_lowl_hid=no
 need_lowl_pci=no
 need_lowl_pci=no
 need_lowl_spi=no
 need_lowl_spi=no
 need_lowl_usb=no
 need_lowl_usb=no
+need_work2d=no
 have_cygwin=false
 have_cygwin=false
 have_win32=false
 have_win32=false
 have_macho=false
 have_macho=false
@@ -581,6 +582,9 @@ if test "x$libevent" != "xno"; then
 			AC_MSG_WARN([libevent 2.0.3+ not found; stratum proxy will be unavailable])
 			AC_MSG_WARN([libevent 2.0.3+ not found; stratum proxy will be unavailable])
 		fi
 		fi
 	])
 	])
+	if test "x$libevent" = "xyes"; then
+		need_work2d=yes
+	fi
 fi
 fi
 AM_CONDITIONAL([USE_LIBEVENT], [test x$libevent = xyes])
 AM_CONDITIONAL([USE_LIBEVENT], [test x$libevent = xyes])
 
 
@@ -1327,6 +1331,7 @@ AM_CONDITIONAL([NEED_BFG_LOWL_HID], [test x$need_lowl_hid = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWL_PCI], [test x$need_lowl_pci = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWL_PCI], [test x$need_lowl_pci = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWL_SPI], [test x$need_lowl_spi = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWL_SPI], [test x$need_lowl_spi = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWLEVEL], [test x$need_lowlevel = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWLEVEL], [test x$need_lowlevel = xyes])
+AM_CONDITIONAL([NEED_BFG_WORK2D], [test x$need_work2d = xyes])
 AM_CONDITIONAL([HAS_SCRYPT], [test x$scrypt = xyes])
 AM_CONDITIONAL([HAS_SCRYPT], [test x$scrypt = xyes])
 AM_CONDITIONAL([HAVE_CURSES], [test x$curses = xyes])
 AM_CONDITIONAL([HAVE_CURSES], [test x$curses = xyes])
 AM_CONDITIONAL([HAVE_SENSORS], [test x$with_sensors = xyes])
 AM_CONDITIONAL([HAVE_SENSORS], [test x$with_sensors = xyes])

+ 14 - 49
driver-stratum.c

@@ -42,12 +42,8 @@ static notifier_t _ssm_update_notifier;
 struct stratumsrv_job {
 struct stratumsrv_job {
 	char *my_job_id;
 	char *my_job_id;
 	
 	
-	struct pool *pool;
-	uint8_t work_restart_id;
-	uint8_t n2size;
 	struct timeval tv_prepared;
 	struct timeval tv_prepared;
 	struct stratum_work swork;
 	struct stratum_work swork;
-	char *nonce1;
 	
 	
 	UT_hash_handle hh;
 	UT_hash_handle hh;
 };
 };
@@ -71,31 +67,7 @@ struct stratumsrv_conn {
 
 
 static struct stratumsrv_conn *_ssm_connections;
 static struct stratumsrv_conn *_ssm_connections;
 
 
-static
-void _ssm_gen_dummy_work(struct work *work, struct stratumsrv_job *ssj, const char * const extranonce2, uint32_t xnonce1)
-{
-	uint8_t *p, *s;
-	
-	*work = (struct work){
-		.pool = ssj->pool,
-		.work_restart_id = ssj->work_restart_id,
-		.tv_staged = ssj->tv_prepared,
-	};
-	bytes_resize(&work->nonce2, ssj->n2size);
-	s = bytes_buf(&work->nonce2);
-	p = &s[ssj->n2size - _ssm_client_xnonce2sz];
-	if (extranonce2)
-		hex2bin(p, extranonce2, _ssm_client_xnonce2sz);
-#ifndef __OPTIMIZE__
-	else
-		memset(p, '\0', _ssm_client_xnonce2sz);
-#endif
-	p -= _ssm_client_octets;
-	memcpy(p, &xnonce1, _ssm_client_octets);
-	if (p != s)
-		memset(s, '\xbb', p - s);
-	gen_stratum_work2(work, &ssj->swork, ssj->nonce1);
-}
+#define _ssm_gen_dummy_work work2d_gen_dummy_work
 
 
 static
 static
 bool stratumsrv_update_notify_str(struct pool * const pool, bool clean)
 bool stratumsrv_update_notify_str(struct pool * const pool, bool clean)
@@ -104,11 +76,11 @@ bool stratumsrv_update_notify_str(struct pool * const pool, bool clean)
 	
 	
 	struct stratumsrv_conn *conn;
 	struct stratumsrv_conn *conn;
 	const struct stratum_work * const swork = &pool->swork;
 	const struct stratum_work * const swork = &pool->swork;
-	const int n2size = pool->n2size;
+	const int n2size = pool->swork.n2size;
 	char my_job_id[33];
 	char my_job_id[33];
 	int i;
 	int i;
 	struct stratumsrv_job *ssj;
 	struct stratumsrv_job *ssj;
-	ssize_t n2pad = n2size - _ssm_client_octets - _ssm_client_xnonce2sz;
+	ssize_t n2pad = work2d_pad_xnonce_size(swork);
 	if (n2pad < 0)
 	if (n2pad < 0)
 		return false;
 		return false;
 	size_t coinb1in_lenx = swork->nonce2_offset * 2;
 	size_t coinb1in_lenx = swork->nonce2_offset * 2;
@@ -124,7 +96,7 @@ bool stratumsrv_update_notify_str(struct pool * const pool, bool clean)
 	uint32_t ntime_n;
 	uint32_t ntime_n;
 	bin2hex(prevhash, &swork->header1[4], 32);
 	bin2hex(prevhash, &swork->header1[4], 32);
 	bin2hex(coinb1, bytes_buf(&swork->coinbase), swork->nonce2_offset);
 	bin2hex(coinb1, bytes_buf(&swork->coinbase), swork->nonce2_offset);
-	memset(&coinb1[coinb1in_lenx], 'B', n2padx);
+	work2d_pad_xnonce(&coinb1[coinb1in_lenx], swork, true);
 	coinb1[coinb1_lenx] = '\0';
 	coinb1[coinb1_lenx] = '\0';
 	bin2hex(coinb2, &bytes_buf(&swork->coinbase)[swork->nonce2_offset + n2size], coinb2_len);
 	bin2hex(coinb2, &bytes_buf(&swork->coinbase)[swork->nonce2_offset + n2size], coinb2_len);
 	p += sprintf(p, "{\"params\":[\"%s\",\"%s\",\"%s\",\"%s\",[", my_job_id, prevhash, coinb1, coinb2);
 	p += sprintf(p, "{\"params\":[\"%s\",\"%s\",\"%s\",\"%s\",[", my_job_id, prevhash, coinb1, coinb2);
@@ -146,11 +118,6 @@ bool stratumsrv_update_notify_str(struct pool * const pool, bool clean)
 	ssj = malloc(sizeof(*ssj));
 	ssj = malloc(sizeof(*ssj));
 	*ssj = (struct stratumsrv_job){
 	*ssj = (struct stratumsrv_job){
 		.my_job_id = strdup(my_job_id),
 		.my_job_id = strdup(my_job_id),
-		
-		.pool = pool,
-		.work_restart_id = pool->work_restart_id,
-		.n2size = n2size,
-		.nonce1 = maybe_strdup(pool->nonce1),
 	};
 	};
 	timer_set_now(&ssj->tv_prepared);
 	timer_set_now(&ssj->tv_prepared);
 	stratum_work_cpy(&ssj->swork, swork);
 	stratum_work_cpy(&ssj->swork, swork);
@@ -162,7 +129,7 @@ bool stratumsrv_update_notify_str(struct pool * const pool, bool clean)
 	
 	
 	if (likely(_ssm_cur_job_work.pool))
 	if (likely(_ssm_cur_job_work.pool))
 		clean_work(&_ssm_cur_job_work);
 		clean_work(&_ssm_cur_job_work);
-	_ssm_gen_dummy_work(&_ssm_cur_job_work, ssj, NULL, 0);
+	_ssm_gen_dummy_work(&_ssm_cur_job_work, &ssj->swork, &ssj->tv_prepared, NULL, 0);
 	
 	
 	_ssm_notify_sz = p - buf;
 	_ssm_notify_sz = p - buf;
 	assert(_ssm_notify_sz <= bufsz);
 	assert(_ssm_notify_sz <= bufsz);
@@ -184,7 +151,6 @@ void _ssj_free(struct stratumsrv_job * const ssj)
 {
 {
 	free(ssj->my_job_id);
 	free(ssj->my_job_id);
 	stratum_work_clean(&ssj->swork);
 	stratum_work_clean(&ssj->swork);
-	free(ssj->nonce1);
 	free(ssj);
 	free(ssj);
 }
 }
 
 
@@ -392,7 +358,6 @@ static
 void stratumsrv_mining_submit(struct bufferevent *bev, json_t *params, const char *idstr, struct stratumsrv_conn * const conn)
 void stratumsrv_mining_submit(struct bufferevent *bev, json_t *params, const char *idstr, struct stratumsrv_conn * const conn)
 {
 {
 	uint32_t * const xnonce1_p = &conn->xnonce1_le;
 	uint32_t * const xnonce1_p = &conn->xnonce1_le;
-	struct work _work, *work;
 	struct stratumsrv_job *ssj;
 	struct stratumsrv_job *ssj;
 	struct proxy_client *client = stratumsrv_find_or_create_client(__json_array_string(params, 0));
 	struct proxy_client *client = stratumsrv_find_or_create_client(__json_array_string(params, 0));
 	struct cgpu_info *cgpu;
 	struct cgpu_info *cgpu;
@@ -401,7 +366,10 @@ void stratumsrv_mining_submit(struct bufferevent *bev, json_t *params, const cha
 	const char * const extranonce2 = __json_array_string(params, 2);
 	const char * const extranonce2 = __json_array_string(params, 2);
 	const char * const ntime = __json_array_string(params, 3);
 	const char * const ntime = __json_array_string(params, 3);
 	const char * const nonce = __json_array_string(params, 4);
 	const char * const nonce = __json_array_string(params, 4);
-	uint32_t nonce_n;
+	uint8_t xnonce2[work2d_xnonce2sz];
+	uint32_t ntime_n, nonce_n;
+	const float nonce_diff = 1;
+	bool is_stale;
 	
 	
 	if (unlikely(!client))
 	if (unlikely(!client))
 		return_stratumsrv_failure(20, "Failed creating new cgpu");
 		return_stratumsrv_failure(20, "Failed creating new cgpu");
@@ -422,24 +390,21 @@ void stratumsrv_mining_submit(struct bufferevent *bev, json_t *params, const cha
 	if (!ssj)
 	if (!ssj)
 		return_stratumsrv_failure(21, "Job not found");
 		return_stratumsrv_failure(21, "Job not found");
 	
 	
-	// Generate dummy work
-	work = &_work;
-	_ssm_gen_dummy_work(work, ssj, extranonce2, *xnonce1_p);
+	hex2bin(xnonce2, extranonce2, work2d_xnonce2sz);
 	
 	
 	// Submit nonce
 	// Submit nonce
-	hex2bin(&work->data[68], ntime, 4);
+	hex2bin((void*)&ntime_n, ntime, 4);
+	ntime_n = be32toh(ntime_n);
 	hex2bin((void*)&nonce_n, nonce, 4);
 	hex2bin((void*)&nonce_n, nonce, 4);
 	nonce_n = le32toh(nonce_n);
 	nonce_n = le32toh(nonce_n);
-	if (!submit_nonce(thr, work, nonce_n))
+	if (!work2d_submit_nonce(thr, &ssj->swork, &ssj->tv_prepared, xnonce2, *xnonce1_p, nonce_n, ntime_n, &is_stale, nonce_diff))
 		_stratumsrv_failure(bev, idstr, 23, "H-not-zero");
 		_stratumsrv_failure(bev, idstr, 23, "H-not-zero");
 	else
 	else
-	if (stale_work(work, true))
+	if (is_stale)
 		_stratumsrv_failure(bev, idstr, 21, "stale");
 		_stratumsrv_failure(bev, idstr, 21, "stale");
 	else
 	else
 		_stratumsrv_success(bev, idstr);
 		_stratumsrv_success(bev, idstr);
 	
 	
-	clean_work(work);
-	
 	if (!conn->hashes_done_ext)
 	if (!conn->hashes_done_ext)
 	{
 	{
 		struct timeval tv_now, tv_delta;
 		struct timeval tv_now, tv_delta;

+ 17 - 9
miner.c

@@ -1048,6 +1048,7 @@ struct pool *add_pool(void)
 	cglock_init(&pool->data_lock);
 	cglock_init(&pool->data_lock);
 	mutex_init(&pool->stratum_lock);
 	mutex_init(&pool->stratum_lock);
 	timer_unset(&pool->swork.tv_transparency);
 	timer_unset(&pool->swork.tv_transparency);
+	pool->swork.pool = pool;
 
 
 	/* Make sure the pool doesn't think we've been idle since time 0 */
 	/* Make sure the pool doesn't think we've been idle since time 0 */
 	pool->tv_idle.tv_sec = ~0UL;
 	pool->tv_idle.tv_sec = ~0UL;
@@ -3030,8 +3031,9 @@ static bool work_decode(struct pool *pool, struct work *work, json_t *val)
 			free(swork->job_id);
 			free(swork->job_id);
 			swork->job_id = NULL;
 			swork->job_id = NULL;
 			swork->clean = true;
 			swork->clean = true;
+			swork->work_restart_id = pool->work_restart_id;
 			// FIXME: Do something with expire
 			// FIXME: Do something with expire
-			pool->nonce2sz = pool->n2size = GBT_XNONCESZ;
+			pool->nonce2sz = swork->n2size = GBT_XNONCESZ;
 			pool->nonce2 = 0;
 			pool->nonce2 = 0;
 			cg_wunlock(&pool->data_lock);
 			cg_wunlock(&pool->data_lock);
 		}
 		}
@@ -5925,7 +5927,7 @@ next_write_sws:
 			cg_rlock(&pool->data_lock);
 			cg_rlock(&pool->data_lock);
 			// NOTE: cgminer only does this check on retries, but BFGMiner does it for even the first/normal submit; therefore, it needs to be such that it always is true on the same connection regardless of session management
 			// NOTE: cgminer only does this check on retries, but BFGMiner does it for even the first/normal submit; therefore, it needs to be such that it always is true on the same connection regardless of session management
 			// NOTE: Worst case scenario for a false positive: the pool rejects it as H-not-zero
 			// NOTE: Worst case scenario for a false positive: the pool rejects it as H-not-zero
-			sessionid_match = (!pool->nonce1) || !strcmp(work->nonce1, pool->nonce1);
+			sessionid_match = (!pool->swork.nonce1) || !strcmp(work->nonce1, pool->swork.nonce1);
 			cg_runlock(&pool->data_lock);
 			cg_runlock(&pool->data_lock);
 			if (!sessionid_match)
 			if (!sessionid_match)
 			{
 			{
@@ -6546,6 +6548,8 @@ static bool test_work_current(struct work *work)
 		{
 		{
 			struct pool * const cp = current_pool();
 			struct pool * const cp = current_pool();
 			++pool->work_restart_id;
 			++pool->work_restart_id;
+			if (work->tr && work->tr == pool->swork.tr)
+				pool->swork.work_restart_id = pool->work_restart_id;
 			update_last_work(work);
 			update_last_work(work);
 			pool_update_work_restart_time(pool);
 			pool_update_work_restart_time(pool);
 			applog(
 			applog(
@@ -8515,6 +8519,7 @@ static void *stratum_thread(void *userdata)
 				have_block_height(block_id, height);
 				have_block_height(block_id, height);
 			}
 			}
 
 
+			pool->swork.work_restart_id =
 			++pool->work_restart_id;
 			++pool->work_restart_id;
 			pool_update_work_restart_time(pool);
 			pool_update_work_restart_time(pool);
 			if (test_work_current(work)) {
 			if (test_work_current(work)) {
@@ -8993,6 +8998,7 @@ void stratum_work_cpy(struct stratum_work * const dst, const struct stratum_work
 	*dst = *src;
 	*dst = *src;
 	if (dst->tr)
 	if (dst->tr)
 		tmpl_incref(dst->tr);
 		tmpl_incref(dst->tr);
+	dst->nonce1 = maybe_strdup(src->nonce1);
 	dst->job_id = maybe_strdup(src->job_id);
 	dst->job_id = maybe_strdup(src->job_id);
 	bytes_cpy(&dst->coinbase, &src->coinbase);
 	bytes_cpy(&dst->coinbase, &src->coinbase);
 	bytes_cpy(&dst->merkle_bin, &src->merkle_bin);
 	bytes_cpy(&dst->merkle_bin, &src->merkle_bin);
@@ -9002,6 +9008,7 @@ void stratum_work_clean(struct stratum_work * const swork)
 {
 {
 	if (swork->tr)
 	if (swork->tr)
 		tmpl_decref(swork->tr);
 		tmpl_decref(swork->tr);
+	free(swork->nonce1);
 	free(swork->job_id);
 	free(swork->job_id);
 	bytes_free(&swork->coinbase);
 	bytes_free(&swork->coinbase);
 	bytes_free(&swork->merkle_bin);
 	bytes_free(&swork->merkle_bin);
@@ -9029,9 +9036,10 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
 	cg_wlock(&pool->data_lock);
 	cg_wlock(&pool->data_lock);
 	pool->swork.data_lock_p = &pool->data_lock;
 	pool->swork.data_lock_p = &pool->data_lock;
 	
 	
-	bytes_resize(&work->nonce2, pool->n2size);
-	if (pool->nonce2sz < pool->n2size)
-		memset(&bytes_buf(&work->nonce2)[pool->nonce2sz], 0, pool->n2size - pool->nonce2sz);
+	const int n2size = pool->swork.n2size;
+	bytes_resize(&work->nonce2, n2size);
+	if (pool->nonce2sz < n2size)
+		memset(&bytes_buf(&work->nonce2)[pool->nonce2sz], 0, n2size - pool->nonce2sz);
 	memcpy(bytes_buf(&work->nonce2),
 	memcpy(bytes_buf(&work->nonce2),
 #ifdef WORDS_BIGENDIAN
 #ifdef WORDS_BIGENDIAN
 	// NOTE: On big endian, the most significant bits are stored at the end, so skip the LSBs
 	// NOTE: On big endian, the most significant bits are stored at the end, so skip the LSBs
@@ -9043,13 +9051,13 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
 	pool->nonce2++;
 	pool->nonce2++;
 	
 	
 	work->pool = pool;
 	work->pool = pool;
-	work->work_restart_id = work->pool->work_restart_id;
-	gen_stratum_work2(work, &pool->swork, pool->nonce1);
+	work->work_restart_id = pool->swork.work_restart_id;
+	gen_stratum_work2(work, &pool->swork);
 	
 	
 	cgtime(&work->tv_staged);
 	cgtime(&work->tv_staged);
 }
 }
 
 
-void gen_stratum_work2(struct work *work, struct stratum_work *swork, const char *nonce1)
+void gen_stratum_work2(struct work *work, struct stratum_work *swork)
 {
 {
 	unsigned char *coinbase, merkle_root[32], merkle_sha[64];
 	unsigned char *coinbase, merkle_root[32], merkle_sha[64];
 	uint8_t *merkle_bin;
 	uint8_t *merkle_bin;
@@ -9089,7 +9097,7 @@ void gen_stratum_work2(struct work *work, struct stratum_work *swork, const char
 	/* Copy parameters required for share submission */
 	/* Copy parameters required for share submission */
 	memcpy(work->target, swork->target, sizeof(work->target));
 	memcpy(work->target, swork->target, sizeof(work->target));
 	work->job_id = maybe_strdup(swork->job_id);
 	work->job_id = maybe_strdup(swork->job_id);
-	work->nonce1 = maybe_strdup(nonce1);
+	work->nonce1 = maybe_strdup(swork->nonce1);
 	if (swork->data_lock_p)
 	if (swork->data_lock_p)
 		cg_runlock(swork->data_lock_p);
 		cg_runlock(swork->data_lock_p);
 
 

+ 8 - 3
miner.h

@@ -1146,12 +1146,16 @@ struct ntime_roll_limits {
 };
 };
 
 
 struct stratum_work {
 struct stratum_work {
+	// Used only as a session id for resuming
+	char *nonce1;
+	
 	struct bfg_tmpl_ref *tr;
 	struct bfg_tmpl_ref *tr;
 	char *job_id;
 	char *job_id;
 	bool clean;
 	bool clean;
 	
 	
 	bytes_t coinbase;
 	bytes_t coinbase;
 	size_t nonce2_offset;
 	size_t nonce2_offset;
+	int n2size;
 	
 	
 	int merkles;
 	int merkles;
 	bytes_t merkle_bin;
 	bytes_t merkle_bin;
@@ -1172,6 +1176,9 @@ struct stratum_work {
 	bool opaque;
 	bool opaque;
 	
 	
 	cglock_t *data_lock_p;
 	cglock_t *data_lock_p;
+	
+	struct pool *pool;
+	unsigned char work_restart_id;
 };
 };
 
 
 #define RBUFSIZE 8192
 #define RBUFSIZE 8192
@@ -1264,14 +1271,12 @@ struct pool {
 	char *sockbuf;
 	char *sockbuf;
 	size_t sockbuf_size;
 	size_t sockbuf_size;
 	char *sockaddr_url; /* stripped url used for sockaddr */
 	char *sockaddr_url; /* stripped url used for sockaddr */
-	char *nonce1;
 	size_t n1_len;
 	size_t n1_len;
 	uint64_t nonce2;
 	uint64_t nonce2;
 	int nonce2sz;
 	int nonce2sz;
 #ifdef WORDS_BIGENDIAN
 #ifdef WORDS_BIGENDIAN
 	int nonce2off;
 	int nonce2off;
 #endif
 #endif
-	int n2size;
 	char *sessionid;
 	char *sessionid;
 	bool has_stratum;
 	bool has_stratum;
 	bool stratum_active;
 	bool stratum_active;
@@ -1370,7 +1375,7 @@ extern void get_benchmark_work(struct work *);
 extern void stratum_work_cpy(struct stratum_work *dst, const struct stratum_work *src);
 extern void stratum_work_cpy(struct stratum_work *dst, const struct stratum_work *src);
 extern void stratum_work_clean(struct stratum_work *);
 extern void stratum_work_clean(struct stratum_work *);
 extern bool pool_has_usable_swork(const struct pool *);
 extern bool pool_has_usable_swork(const struct pool *);
-extern void gen_stratum_work2(struct work *, struct stratum_work *, const char *nonce1);
+extern void gen_stratum_work2(struct work *, struct stratum_work *);
 extern void inc_hw_errors3(struct thr_info *thr, const struct work *work, const uint32_t *bad_nonce_p, float nonce_diff);
 extern void inc_hw_errors3(struct thr_info *thr, const struct work *work, const uint32_t *bad_nonce_p, float nonce_diff);
 static inline
 static inline
 void inc_hw_errors2(struct thr_info * const thr, const struct work * const work, const uint32_t *bad_nonce_p)
 void inc_hw_errors2(struct thr_info * const thr, const struct work * const work, const uint32_t *bad_nonce_p)

+ 7 - 7
util.c

@@ -2130,12 +2130,12 @@ static bool parse_notify(struct pool *pool, json_t *val)
 	pool->swork.nonce2_offset = cb1_len + pool->n1_len;
 	pool->swork.nonce2_offset = cb1_len + pool->n1_len;
 	cb2_len = strlen(coinbase2) / 2;
 	cb2_len = strlen(coinbase2) / 2;
 
 
-	bytes_resize(&pool->swork.coinbase, pool->swork.nonce2_offset + pool->n2size + cb2_len);
+	bytes_resize(&pool->swork.coinbase, pool->swork.nonce2_offset + pool->swork.n2size + cb2_len);
 	uint8_t *coinbase = bytes_buf(&pool->swork.coinbase);
 	uint8_t *coinbase = bytes_buf(&pool->swork.coinbase);
 	hex2bin(coinbase, coinbase1, cb1_len);
 	hex2bin(coinbase, coinbase1, cb1_len);
-	hex2bin(&coinbase[cb1_len], pool->nonce1, pool->n1_len);
+	hex2bin(&coinbase[cb1_len], pool->swork.nonce1, pool->n1_len);
 	// NOTE: gap for nonce2, filled at work generation time
 	// NOTE: gap for nonce2, filled at work generation time
-	hex2bin(&coinbase[pool->swork.nonce2_offset + pool->n2size], coinbase2, cb2_len);
+	hex2bin(&coinbase[pool->swork.nonce2_offset + pool->swork.n2size], coinbase2, cb2_len);
 	
 	
 	bytes_resize(&pool->swork.merkle_bin, 32 * merkles);
 	bytes_resize(&pool->swork.merkle_bin, 32 * merkles);
 	for (i = 0; i < merkles; i++)
 	for (i = 0; i < merkles; i++)
@@ -2684,10 +2684,10 @@ resend:
 	cg_wlock(&pool->data_lock);
 	cg_wlock(&pool->data_lock);
 	free(pool->sessionid);
 	free(pool->sessionid);
 	pool->sessionid = sessionid;
 	pool->sessionid = sessionid;
-	free(pool->nonce1);
-	pool->nonce1 = nonce1;
+	free(pool->swork.nonce1);
+	pool->swork.nonce1 = nonce1;
 	pool->n1_len = strlen(nonce1) / 2;
 	pool->n1_len = strlen(nonce1) / 2;
-	pool->n2size = n2size;
+	pool->swork.n2size = n2size;
 	pool->nonce2sz  = (n2size > sizeof(pool->nonce2)) ? sizeof(pool->nonce2) : n2size;
 	pool->nonce2sz  = (n2size > sizeof(pool->nonce2)) ? sizeof(pool->nonce2) : n2size;
 #ifdef WORDS_BIGENDIAN
 #ifdef WORDS_BIGENDIAN
 	pool->nonce2off = (n2size < sizeof(pool->nonce2)) ? (sizeof(pool->nonce2) - n2size) : 0;
 	pool->nonce2off = (n2size < sizeof(pool->nonce2)) ? (sizeof(pool->nonce2) - n2size) : 0;
@@ -2712,7 +2712,7 @@ out:
 		set_target_to_pdiff(pool->swork.target, 1);
 		set_target_to_pdiff(pool->swork.target, 1);
 		if (opt_protocol) {
 		if (opt_protocol) {
 			applog(LOG_DEBUG, "Pool %d confirmed mining.subscribe with extranonce1 %s extran2size %d",
 			applog(LOG_DEBUG, "Pool %d confirmed mining.subscribe with extranonce1 %s extran2size %d",
-			       pool->pool_no, pool->nonce1, pool->n2size);
+			       pool->pool_no, pool->swork.nonce1, pool->swork.n2size);
 		}
 		}
 	} else {
 	} else {
 		if (recvd)
 		if (recvd)

+ 70 - 0
work2d.c

@@ -11,8 +11,10 @@
 
 
 #include <stdbool.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdint.h>
+#include <string.h>
 
 
 #include "miner.h"
 #include "miner.h"
+#include "util.h"
 
 
 #define MAX_DIVISIONS 255
 #define MAX_DIVISIONS 255
 
 
@@ -45,3 +47,71 @@ void release_work2d_(uint32_t xnonce1)
 	xnonce1 = le32toh(xnonce1);
 	xnonce1 = le32toh(xnonce1);
 	work2d_reserved[xnonce1] = false;
 	work2d_reserved[xnonce1] = false;
 }
 }
+
+int work2d_pad_xnonce_size(const struct stratum_work * const swork)
+{
+	return swork->n2size - work2d_xnonce1sz - work2d_xnonce2sz;
+}
+
+void *work2d_pad_xnonce(void * const buf_, const struct stratum_work * const swork, const bool hex)
+{
+	uint8_t * const buf = buf_;
+	int pad = work2d_pad_xnonce_size(swork);
+	if (pad < 0)
+		return NULL;
+	if (hex)
+	{
+		pad *= 2;
+		memset(buf, 'b', pad);
+	}
+	else
+		memset(buf, '\xbb', pad);
+	return &buf[pad];
+}
+
+void work2d_gen_dummy_work(struct work * const work, struct stratum_work * const swork, const struct timeval * const tvp_prepared, const void * const xnonce2, const uint32_t xnonce1)
+{
+	uint8_t *p, *s;
+	
+	*work = (struct work){
+		.pool = swork->pool,
+		.work_restart_id = swork->work_restart_id,
+		.tv_staged = *tvp_prepared,
+	};
+	bytes_resize(&work->nonce2, swork->n2size);
+	s = bytes_buf(&work->nonce2);
+	p = &s[swork->n2size - work2d_xnonce2sz];
+	if (xnonce2)
+		memcpy(p, xnonce2, work2d_xnonce2sz);
+#ifndef __OPTIMIZE__
+	else
+		memset(p, '\0', work2d_xnonce2sz);
+#endif
+	p -= work2d_xnonce1sz;
+	memcpy(p, &xnonce1, work2d_xnonce1sz);
+	work2d_pad_xnonce(s, swork, false);
+	gen_stratum_work2(work, swork);
+}
+
+bool work2d_submit_nonce(struct thr_info * const thr, struct stratum_work * const swork, const struct timeval * const tvp_prepared, const void * const xnonce2, const uint32_t xnonce1, const uint32_t nonce, const uint32_t ntime, bool * const out_is_stale, const float nonce_diff)
+{
+	struct work _work, *work;
+	bool rv;
+	
+	// Generate dummy work
+	work = &_work;
+	work2d_gen_dummy_work(work, swork, tvp_prepared, xnonce2, xnonce1);
+	*(uint32_t *)&work->data[68] = htobe32(ntime);
+	work->nonce_diff = nonce_diff;
+	
+	// Check if it's stale, if desired
+	if (out_is_stale)
+		*out_is_stale = stale_work(work, true);
+	
+	// Submit nonce
+	rv = submit_nonce(thr, work, nonce);
+	
+	clean_work(work);
+	
+	return rv;
+}

+ 5 - 0
work2d.h

@@ -11,4 +11,9 @@ extern void work2d_init();
 extern bool reserve_work2d_(uint32_t *xnonce1_p);
 extern bool reserve_work2d_(uint32_t *xnonce1_p);
 extern void release_work2d_(uint32_t xnonce1);
 extern void release_work2d_(uint32_t xnonce1);
 
 
+extern int work2d_pad_xnonce_size(const struct stratum_work *);
+extern void *work2d_pad_xnonce(void *buf, const struct stratum_work *, bool hex);
+extern void work2d_gen_dummy_work(struct work *, struct stratum_work *, const struct timeval *tvp_prepared, const void *xnonce2, uint32_t xnonce1);
+extern bool work2d_submit_nonce(struct thr_info *, struct stratum_work *, const struct timeval *tvp_prepared, const void *xnonce2, uint32_t xnonce1, uint32_t nonce, uint32_t ntime, bool *out_is_stale, float nonce_diff);
+
 #endif
 #endif