Browse Source

Merge pull request #1 from luke-jr/bfgminer

Merge upstream
jstefanop 8 years ago
parent
commit
6382db1d68
18 changed files with 346 additions and 139 deletions
  1. 30 0
      NEWS
  2. 11 13
      README.OpenWrt
  3. 9 5
      api.c
  4. 19 8
      configure.ac
  5. 14 0
      debian/changelog
  6. 1 1
      debian/control
  7. 2 0
      driver-antminer.c
  8. 1 2
      driver-avalonmm.c
  9. 1 1
      driver-bitmain.c
  10. 3 3
      driver-icarus.c
  11. 132 62
      driver-stratum.c
  12. 1 1
      libblkmaker
  13. 70 30
      miner.c
  14. 2 1
      miner.h
  15. 14 2
      openwrt/bfgminer/Makefile
  16. 17 6
      openwrt/multibuild.sh
  17. 18 4
      work2d.c
  18. 1 0
      work2d.h

+ 30 - 0
NEWS

@@ -1,3 +1,33 @@
+BFGMiner Version 5.4.2 - March 26, 2016
+
+- Update official Win32/64 build compiler and libraries:
+- - Win64 compiler (GCC) from 4.7.4 to 5.3.0 (Win32 remains at 4.7.4)
+- - libcurl from 7.39.0 to 7.47.1
+- - libevent from 2.0.21 to 2.1.5-r4
+- - libusb from 1.0.18 (Win32) and 1.0.19 (Win64) to 1.0.20
+- - libmicrohttpd from 0.9.38_pre33603 to 0.9.48
+- Update libblkmaker to 0.5.3
+- Bugfix: Sanitise lock situation for work2d
+- Bugfix: SSM: Never issue the same work2d twice in a row
+- Bugfix: SSM: Never send mining.notify for stale work2d
+- SSM: Refactor work2d check and job pruning from _stratumsrv_update_notify
+into stratumsrv_update_notify_str
+- Updates for OpenWrt 15.05
+- Bugfix: Correct work2d handling for GBT servers
+
+
+BFGMiner Version 5.4.1 - November 21, 2015
+
+- bitmain: Use more portable PRIu64 rather than %llu (which fails on Windows)
+- icarus: Use more portable PRIu64 rather than %llu (which fails on Windows)
+- Bugfix: openwrt: Fix bitmain option
+- Bugfix: antminer: Avoid strstr(NULL, ...) when device has no [available]
+product string
+- Update libblkmaker to 0.5.2
+- openwrt: Add option to enable bitmain driver
+- openwrt: Update libusb device list
+
+
 BFGMiner Version 5.4.0 - October 23, 2015
 BFGMiner Version 5.4.0 - October 23, 2015
 
 
 - AUTHORS: Move jstefanop to current maintainers
 - AUTHORS: Move jstefanop to current maintainers

+ 11 - 13
README.OpenWrt

@@ -1,12 +1,14 @@
-Open up /etc/opkg.conf (on your router) in your favourite editor. You will see
-a line that looks similar to this at the top (depending on your device):
-	src/gz attitude_adjustment http://downloads.openwrt.org/attitude_adjustment/12.09/ar71xx/generic/packages
-Note the platform following the OpenWrt version. In this example, it is ar71xx.
+First, look at /etc/openwrt_release (on your router). You will see a bunch of
+attributes for the OpenWrt system. The DISTRIB_RELEASE attribute is your
+OpenWrt version, and the first part of DISTRIB_TARGET (before the slash) is
+the router's platform.
 
 
-Now add a new line immediately below it, similar to this:
-	src/gz bfgminer http://luke.dashjr.org/programs/bitcoin/files/bfgminer/latest/openwrt/12.09/ar71xx
-Be sure you put the same platform at the end as your OpenWrt repository!
-Also note that you can change "latest" to "stable" or "testing" to get better-tested versions.
+Now, open up /etc/opkg.conf (again, on your router) in your favourite editor.
+Add a new line at the bottom, similar to this:
+	src/gz bfgminer http://luke.dashjr.org/programs/bitcoin/files/bfgminer/latest/openwrt/15.05/ar71xx
+In this example, 15.05 is the version of OpenWrt, and ar71xx is the platform.
+Be sure to change those to match your router! You can also change "latest" to
+"stable" or "testing" to get better-tested versions.
 
 
 Next, save the file and exit your editor. Tell opkg to reload its package lists
 Next, save the file and exit your editor. Tell opkg to reload its package lists
 by running the command:
 by running the command:
@@ -16,12 +18,8 @@ you open an issue for your router's platform, it may be possible to add
 support.
 support.
 
 
 If all went well updating your package list, you can now install BFGMiner and
 If all went well updating your package list, you can now install BFGMiner and
-any drivers and/or bitstreams you might need:
+any drivers you might need:
 	opkg install bfgminer
 	opkg install bfgminer
 	opkg install kmod-usb-serial-ftdi
 	opkg install kmod-usb-serial-ftdi
 	opkg install kmod-usb-serial-cp210x
 	opkg install kmod-usb-serial-cp210x
 	opkg install kmod-usb-serial-pl2303
 	opkg install kmod-usb-serial-pl2303
-	opkg find bitstream*
-	opkg install bitstream-ztex-ufm1_15y1
-	opkg install bitstream-ztex-ufm1_15b1
-	opkg install bitstream-fpgaminer

+ 9 - 5
api.c

@@ -313,6 +313,7 @@ static const char *JSON_PARAMETER = "parameter";
 #define MSG_SETQUOTA 122
 #define MSG_SETQUOTA 122
 
 
 #define MSG_INVSTRATEGY 0x102
 #define MSG_INVSTRATEGY 0x102
+#define MSG_FAILPORT 0x103
 
 
 #define USE_ALTMSG 0x4000
 #define USE_ALTMSG 0x4000
 
 
@@ -466,6 +467,7 @@ struct CODES {
  { SEVERITY_ERR,   MSG_INVNUM,	PARAM_BOTH,	"Invalid number (%d) for '%s' range is 0-9999" },
  { SEVERITY_ERR,   MSG_INVNUM,	PARAM_BOTH,	"Invalid number (%d) for '%s' range is 0-9999" },
  { SEVERITY_ERR,   MSG_INVNEG,	PARAM_BOTH,	"Invalid negative number (%d) for '%s'" },
  { SEVERITY_ERR,   MSG_INVNEG,	PARAM_BOTH,	"Invalid negative number (%d) for '%s'" },
  { SEVERITY_ERR,   MSG_INVSTRATEGY,	PARAM_STR,	"Invalid strategy for '%s'" },
  { SEVERITY_ERR,   MSG_INVSTRATEGY,	PARAM_STR,	"Invalid strategy for '%s'" },
+ { SEVERITY_ERR,   MSG_FAILPORT,	PARAM_BOTH,	"Failed to set port (%d) for '%s'" },
  { SEVERITY_SUCC,  MSG_SETQUOTA,PARAM_SET,	"Set pool '%s' to quota %d'" },
  { SEVERITY_SUCC,  MSG_SETQUOTA,PARAM_SET,	"Set pool '%s' to quota %d'" },
  { SEVERITY_ERR,   MSG_CONPAR,	PARAM_NONE,	"Missing config parameters 'name,N'" },
  { SEVERITY_ERR,   MSG_CONPAR,	PARAM_NONE,	"Missing config parameters 'name,N'" },
  { SEVERITY_ERR,   MSG_CONVAL,	PARAM_STR,	"Missing config value N for '%s,N'" },
  { SEVERITY_ERR,   MSG_CONVAL,	PARAM_STR,	"Missing config value N for '%s,N'" },
@@ -3203,12 +3205,12 @@ static void debugstate(struct io_data *io_data, __maybe_unused SOCKETTYPE c, cha
 		io_close(io_data);
 		io_close(io_data);
 }
 }
 
 
-extern void stratumsrv_change_port();
+extern bool stratumsrv_change_port(unsigned);
 
 
 static void setconfig(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
 static void setconfig(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
 {
 {
 	char *comma;
 	char *comma;
-	int value;
+	long value;
 
 
 	if (param == NULL || *param == '\0') {
 	if (param == NULL || *param == '\0') {
 		message(io_data, MSG_CONPAR, 0, NULL, isjson);
 		message(io_data, MSG_CONPAR, 0, NULL, isjson);
@@ -3251,7 +3253,7 @@ static void setconfig(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char
 		return;
 		return;
 	}
 	}
 
 
-	value = atoi(comma);
+	value = atol(comma);
 	if (value < 0 || value > 9999) {
 	if (value < 0 || value > 9999) {
 		message(io_data, MSG_INVNUM, value, param, isjson);
 		message(io_data, MSG_INVNUM, value, param, isjson);
 		return;
 		return;
@@ -3275,8 +3277,10 @@ static void setconfig(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char
 #ifdef USE_LIBEVENT
 #ifdef USE_LIBEVENT
 	else if (strcasecmp(param, "stratum-port") == 0)
 	else if (strcasecmp(param, "stratum-port") == 0)
 	{
 	{
-		stratumsrv_port = value;
-		stratumsrv_change_port();
+		if (!stratumsrv_change_port(value)) {
+			message(io_data, MSG_FAILPORT, value, param, isjson);
+			return;
+		}
 	}
 	}
 #endif
 #endif
 	else {
 	else {

+ 19 - 8
configure.ac

@@ -15,7 +15,7 @@ dnl * any later version.  See COPYING for more details.
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_maj], [5])
 m4_define([v_maj], [5])
 m4_define([v_min], [4])
 m4_define([v_min], [4])
-m4_define([v_mic], [0])
+m4_define([v_mic], [2])
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_ver], [v_maj.v_min.v_mic])
 m4_define([v_ver], [v_maj.v_min.v_mic])
 m4_define([lt_rev], m4_eval(v_maj + v_min))
 m4_define([lt_rev], m4_eval(v_maj + v_min))
@@ -223,7 +223,7 @@ m4_define([BFG_FIND_INCLUDE_PATH],[
 	m4_pushdef([_result_var],[inclpath_[]patsubst(_header_file,[[./]],[_])])
 	m4_pushdef([_result_var],[inclpath_[]patsubst(_header_file,[[./]],[_])])
 	AC_CHECK_HEADER([_rel_path/_header_file],[
 	AC_CHECK_HEADER([_rel_path/_header_file],[
 		AC_MSG_CHECKING([_header_file path])
 		AC_MSG_CHECKING([_header_file path])
-		_result_var=`echo '[#]include <'"_rel_path"'/_header_file>' | ${CPP} -M - 2>/dev/null | ${SED} [-E -e ':a' -e '/\\$/!b b' -e N -e 's/\\\n/ /' -e 't a' -e ':b' -e 's/^[^:]*:[[:space:]]*(([^[:space:]\]|\\.)*[[:space:]])*(([^[:space:]\]|\\.)*)]patsubst([_header_file],[\.],[\\.])[([[:space:]].*)?$/\3/' -e 't' -e d]`
+		_result_var=`echo '[#]include <'"_rel_path"'/_header_file>' | ${CPP} -M - 2>/dev/null | ${SED} [-E -e ':a' -e '/\\$/!b b' -e N -e 's/\\\n/ /' -e 't a' -e ':b' -e 's/^[^:]*:[[:space:]]*(([^[:space:]\]|\\.)*[[:space:]])*(([^[:space:]\]|\\.)*)(\\|\\\\|\/)?]patsubst([_header_file],[\.],[\\.])[([[:space:]].*)?$/\3/' -e 't' -e d]`
 		if test "x$_result_var" = "x"; then
 		if test "x$_result_var" = "x"; then
 			AC_MSG_RESULT([failed])
 			AC_MSG_RESULT([failed])
 			AC_MSG_ERROR([Couldn't determine include path for _header_file])
 			AC_MSG_ERROR([Couldn't determine include path for _header_file])
@@ -661,10 +661,23 @@ AC_ARG_WITH([libevent],
 )
 )
 if test "x$libevent" != "xno"; then
 if test "x$libevent" != "xno"; then
 	PKG_CHECK_MODULES([libevent],[libevent >= 2.0.3],[
 	PKG_CHECK_MODULES([libevent],[libevent >= 2.0.3],[
-		AC_DEFINE([USE_LIBEVENT],[1],[Defined to 1 if libevent support is wanted])
+		PKG_CHECK_MODULES([libevent_pthreads],[libevent_pthreads],[
+			libevent_CFLAGS="${libevent_CFLAGS} ${libevent_pthreads_CFLAGS}"
+			libevent_LIBS="${libevent_LIBS} ${libevent_pthreads_LIBS}"
+		],[true])
+		AC_MSG_CHECKING([if libevent supports threading])
+		BFG_PREPROC_IFELSE([EVTHREAD_USE_PTHREADS_IMPLEMENTED || EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED],[event2/thread.h],[
+			AC_MSG_RESULT([yes])
+			have_libevent=yes
+		],[
+			AC_MSG_RESULT([no])
+		])
+	])
+	if test "x$have_libevent" = "xyes"; then
 		libevent=yes
 		libevent=yes
-	],[
-		libevent=no
+		need_work2d=yes
+		AC_DEFINE([USE_LIBEVENT],[1],[Defined to 1 if libevent support is wanted])
+	else
 		libevent_enableaction="install libevent 2.0.3+"
 		libevent_enableaction="install libevent 2.0.3+"
 		if test -n "$need_bfg_driver_proxy_enableaction"; then
 		if test -n "$need_bfg_driver_proxy_enableaction"; then
 			need_bfg_driver_proxy_enableaction="${need_bfg_driver_proxy_enableaction} (getwork) or libevent 2.0.3+ (stratum)"
 			need_bfg_driver_proxy_enableaction="${need_bfg_driver_proxy_enableaction} (getwork) or libevent 2.0.3+ (stratum)"
@@ -676,9 +689,7 @@ if test "x$libevent" != "xno"; then
 		else
 		else
 			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
+		libevent=no
 	fi
 	fi
 fi
 fi
 AM_CONDITIONAL([USE_LIBEVENT], [test x$libevent = xyes])
 AM_CONDITIONAL([USE_LIBEVENT], [test x$libevent = xyes])

+ 14 - 0
debian/changelog

@@ -1,3 +1,17 @@
+bfgminer (5.4.2-0precise1) precise; urgency=low
+
+  * Fix some possible edge case problems with stratum proxying (--stratum-port)
+  * openwrt: Binary packages for 15.05
+  * Fix 2D work support for GBT servers (requires libblkmaker 0.5.3 or newer)
+
+ -- Luke Dashjr <luke+bfgminer@dashjr.org>  Sat, 26 Mar 2016 06:52:15 -0000
+
+bfgminer (5.4.1-0precise1) precise; urgency=low
+
+  * Bugfixes only.
+
+ -- Luke Dashjr <luke+bfgminer@dashjr.org>  Sat, 21 Nov 2015 18:12:26 -0000
+
 bfgminer (5.4.0-0precise1) precise; urgency=low
 bfgminer (5.4.0-0precise1) precise; urgency=low
 
 
   * RPC: Ability to change pool management strategy.
   * RPC: Ability to change pool management strategy.

+ 1 - 1
debian/control

@@ -2,7 +2,7 @@ Source: bfgminer
 Priority: optional
 Priority: optional
 Section: misc
 Section: misc
 Maintainer: Luke Dashjr <luke_bfgminer@dashjr.org>
 Maintainer: Luke Dashjr <luke_bfgminer@dashjr.org>
-Standards-Version: 5.4.0
+Standards-Version: 5.4.2
 Build-Depends: build-essential, debhelper, autoconf, automake, libtool, libssl-dev, yasm, pkg-config, libudev-dev, libcurl4-openssl-dev, wget, unzip, libjansson-dev, libncurses5-dev, libudev-dev, libusb-1.0-0-dev, git, quilt, uthash-dev, libsensors4-dev
 Build-Depends: build-essential, debhelper, autoconf, automake, libtool, libssl-dev, yasm, pkg-config, libudev-dev, libcurl4-openssl-dev, wget, unzip, libjansson-dev, libncurses5-dev, libudev-dev, libusb-1.0-0-dev, git, quilt, uthash-dev, libsensors4-dev
 
 
 Package: bfgminer
 Package: bfgminer

+ 2 - 0
driver-antminer.c

@@ -50,6 +50,8 @@ static const char *bm1382_chips[] = {
 
 
 static bool antminer_chip_has_bm1382_freq_register(const char * const prodstr)
 static bool antminer_chip_has_bm1382_freq_register(const char * const prodstr)
 {
 {
+	if (!prodstr)
+		return false;
 	for (const char **chipname = bm1382_chips; *chipname; ++chipname) {
 	for (const char **chipname = bm1382_chips; *chipname; ++chipname) {
 		if (strstr(prodstr, *chipname)) {
 		if (strstr(prodstr, *chipname)) {
 			return true;
 			return true;

+ 1 - 2
driver-avalonmm.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2014 Luke Dashjr
+ * Copyright 2014-2016 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
  * under the terms of the GNU General Public License as published by the Free
@@ -509,7 +509,6 @@ bool avalonmm_update_swork_from_pool(struct cgpu_info * const master_dev, struct
 	stratum_work_cpy(&mmjob->swork, &pool->swork);
 	stratum_work_cpy(&mmjob->swork, &pool->swork);
 	cg_runlock(&pool->data_lock);
 	cg_runlock(&pool->data_lock);
 	timer_set_now(&mmjob->tv_prepared);
 	timer_set_now(&mmjob->tv_prepared);
-	mmjob->swork.data_lock_p = NULL;
 	if (!avalonmm_send_swork(fd, chain, &mmjob->swork, mmjob->jobid, &mmjob->nonce_diff))
 	if (!avalonmm_send_swork(fd, chain, &mmjob->swork, mmjob->jobid, &mmjob->nonce_diff))
 	{
 	{
 		avalonmm_free_job(mmjob);
 		avalonmm_free_job(mmjob);

+ 1 - 1
driver-bitmain.c

@@ -671,7 +671,7 @@ static int bitmain_read(struct cgpu_info *bitmain, unsigned char *buf,
 	size_t total = 0;
 	size_t total = 0;
 
 
 	if(bitmain == NULL || buf == NULL || bufsize <= 0) {
 	if(bitmain == NULL || buf == NULL || bufsize <= 0) {
-		applog(LOG_WARNING, "bitmain_read parameter error bufsize(%llu)", (unsigned long long)bufsize);
+		applog(LOG_WARNING, "bitmain_read parameter error bufsize(%"PRIu64")", (uint64_t)bufsize);
 		return -1;
 		return -1;
 	}
 	}
 	{
 	{

+ 3 - 3
driver-icarus.c

@@ -756,7 +756,7 @@ const struct cgpu_info *icarus_proc_for_nonce(const struct cgpu_info * const ica
 	struct ICARUS_INFO * const info = icarus->device_data;
 	struct ICARUS_INFO * const info = icarus->device_data;
 	unsigned proc_id = 0;
 	unsigned proc_id = 0;
 	for (int i = info->work_division, j = 0; i /= 2; ++j)
 	for (int i = info->work_division, j = 0; i /= 2; ++j)
-		if (nonce & (1 << (31 - j)))
+		if (nonce & (1UL << (31 - j)))
 			proc_id |= (1 << j);
 			proc_id |= (1 << j);
 	const struct cgpu_info * const proc = device_proc_by_id(icarus, proc_id) ?: icarus;
 	const struct cgpu_info * const proc = device_proc_by_id(icarus, proc_id) ?: icarus;
 	return proc;
 	return proc;
@@ -1102,12 +1102,12 @@ keepwaiting:
 		{
 		{
 			const uint64_t elapsed_fs = (elapsed.tv_sec * 1000000000000000LL) + (elapsed.tv_usec * 1000000000LL);
 			const uint64_t elapsed_fs = (elapsed.tv_sec * 1000000000000000LL) + (elapsed.tv_usec * 1000000000LL);
 			const uint64_t est_Hs_fs = elapsed_fs / hash_count;
 			const uint64_t est_Hs_fs = elapsed_fs / hash_count;
-			applog(LOG_DEBUG, "%"PRIpreprv" nonce = 0x%08x = 0x%08" PRIx64 " hashes (%"PRId64".%06lus; %llu.%06luns/hash)",
+			applog(LOG_DEBUG, "%"PRIpreprv" nonce = 0x%08x = 0x%08" PRIx64 " hashes (%"PRId64".%06lus; %"PRIu64".%06luns/hash)",
 			       proc->proc_repr,
 			       proc->proc_repr,
 			       nonce,
 			       nonce,
 			       (uint64_t)hash_count,
 			       (uint64_t)hash_count,
 			       (int64_t)elapsed.tv_sec, (unsigned long)elapsed.tv_usec,
 			       (int64_t)elapsed.tv_sec, (unsigned long)elapsed.tv_usec,
-			       (unsigned long long)(est_Hs_fs / 1000000LL), (unsigned long)(est_Hs_fs % 1000000LL));
+			       (uint64_t)(est_Hs_fs / 1000000LL), (unsigned long)(est_Hs_fs % 1000000LL));
 		}
 		}
 	}
 	}
 	else
 	else

+ 132 - 62
driver-stratum.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2013-2014 Luke Dashjr
+ * Copyright 2013-2016 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
  * under the terms of the GNU General Public License as published by the Free
@@ -24,6 +24,7 @@
 #include <event2/bufferevent.h>
 #include <event2/bufferevent.h>
 #include <event2/event.h>
 #include <event2/event.h>
 #include <event2/listener.h>
 #include <event2/listener.h>
+#include <event2/thread.h>
 
 
 #include <jansson.h>
 #include <jansson.h>
 
 
@@ -101,8 +102,6 @@ void stratumsrv_send_set_difficulty(struct stratumsrv_conn * const conn, const f
 	bufferevent_write(bev, buf, bufsz);
 	bufferevent_write(bev, buf, bufsz);
 }
 }
 
 
-#define _ssm_gen_dummy_work work2d_gen_dummy_work
-
 static
 static
 float stratumsrv_choose_share_pdiff(const struct stratumsrv_conn * const conn, const struct mining_algorithm * const malgo)
 float stratumsrv_choose_share_pdiff(const struct stratumsrv_conn * const conn, const struct mining_algorithm * const malgo)
 {
 {
@@ -112,27 +111,75 @@ float stratumsrv_choose_share_pdiff(const struct stratumsrv_conn * const conn, c
 	return conn_pdiff;
 	return conn_pdiff;
 }
 }
 
 
+static void stratumsrv_boot_all_subscribed(const char *);
+static void _ssj_free(struct stratumsrv_job *);
+static void stratumsrv_job_pruner();
+
 static
 static
-bool stratumsrv_update_notify_str(struct pool * const pool, bool clean)
+bool stratumsrv_update_notify_str(struct pool * const pool)
 {
 {
+	const bool clean = _ssm_cur_job_work.pool ? stale_work(&_ssm_cur_job_work, true) : true;
+	struct timeval tv_now;
+	
 	cg_rlock(&pool->data_lock);
 	cg_rlock(&pool->data_lock);
 	
 	
+	if (!pool_has_usable_swork(pool))
+	{
+fail:
+		cg_runlock(&pool->data_lock);
+		applog(LOG_WARNING, "SSM: No usable 2D work upstream!");
+		if (clean)
+			stratumsrv_boot_all_subscribed("Current upstream pool does not have usable 2D work");
+		return false;
+	}
+	
+	timer_set_now(&tv_now);
+	
+	{
+		struct work work;
+		work2d_gen_dummy_work_for_stale_check(&work, &pool->swork, &tv_now, NULL);
+		
+		const bool is_stale = stale_work(&work, false);
+		
+		clean_work(&work);
+		
+		if (is_stale) {
+			cg_runlock(&pool->data_lock);
+			applog(LOG_DEBUG, "SSM: Ignoring work update notification while pool %d has stale swork", pool->pool_no);
+			return false;
+		}
+	}
+	
 	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->swork.n2size;
 	const int n2size = pool->swork.n2size;
+	const size_t coinb2_offset = swork->nonce2_offset + n2size;
+	const size_t coinb2_len = bytes_len(&swork->coinbase) - swork->nonce2_offset - n2size;
+	
+	if (_ssm_last_ssj &&
+	    !(memcmp(&swork->header1[0], &_ssm_last_ssj->swork.header1[0], 0x24)
+	   || swork->nonce2_offset != _ssm_last_ssj->swork.nonce2_offset
+	   || bytes_len(&swork->coinbase) != bytes_len(&_ssm_last_ssj->swork.coinbase)
+	   || memcmp(bytes_buf(&swork->coinbase), bytes_buf(&_ssm_last_ssj->swork.coinbase), swork->nonce2_offset)
+	   || memcmp(&bytes_buf(&swork->coinbase)[coinb2_offset], &bytes_buf(&_ssm_last_ssj->swork.coinbase)[coinb2_offset], coinb2_len)
+	   || memcmp(swork->diffbits, _ssm_last_ssj->swork.diffbits, 4)
+	)) {
+		cg_runlock(&pool->data_lock);
+		applog(LOG_DEBUG, "SSM: Updating with (near?-)identical work2d; skipping...");
+		return false;
+	}
+	
 	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 = work2d_pad_xnonce_size(swork);
 	ssize_t n2pad = work2d_pad_xnonce_size(swork);
 	if (n2pad < 0)
 	if (n2pad < 0)
 	{
 	{
-		cg_runlock(&pool->data_lock);
-		return false;
+		goto fail;
 	}
 	}
 	size_t coinb1in_lenx = swork->nonce2_offset * 2;
 	size_t coinb1in_lenx = swork->nonce2_offset * 2;
 	size_t n2padx = n2pad * 2;
 	size_t n2padx = n2pad * 2;
 	size_t coinb1_lenx = coinb1in_lenx + n2padx;
 	size_t coinb1_lenx = coinb1in_lenx + n2padx;
-	size_t coinb2_len = bytes_len(&swork->coinbase) - swork->nonce2_offset - n2size;
 	size_t coinb2_lenx = coinb2_len * 2;
 	size_t coinb2_lenx = coinb2_len * 2;
 	sprintf(my_job_id, "%"PRIx64"-%"PRIx64, (uint64_t)time(NULL), _ssm_jobid++);
 	sprintf(my_job_id, "%"PRIx64"-%"PRIx64, (uint64_t)time(NULL), _ssm_jobid++);
 	// NOTE: The buffer has up to 2 extra/unused bytes:
 	// NOTE: The buffer has up to 2 extra/unused bytes:
@@ -147,7 +194,7 @@ bool stratumsrv_update_notify_str(struct pool * const pool, bool clean)
 	bin2hex(coinb1, bytes_buf(&swork->coinbase), swork->nonce2_offset);
 	bin2hex(coinb1, bytes_buf(&swork->coinbase), swork->nonce2_offset);
 	work2d_pad_xnonce(&coinb1[coinb1in_lenx], swork, true);
 	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)[coinb2_offset], 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);
 	for (i = 0; i < swork->merkles; ++i)
 	for (i = 0; i < swork->merkles; ++i)
 	{
 	{
@@ -172,17 +219,30 @@ bool stratumsrv_update_notify_str(struct pool * const pool, bool clean)
 	*ssj = (struct stratumsrv_job){
 	*ssj = (struct stratumsrv_job){
 		.my_job_id = strdup(my_job_id),
 		.my_job_id = strdup(my_job_id),
 	};
 	};
-	timer_set_now(&ssj->tv_prepared);
+	ssj->tv_prepared = tv_now;
 	stratum_work_cpy(&ssj->swork, swork);
 	stratum_work_cpy(&ssj->swork, swork);
 	
 	
 	cg_runlock(&pool->data_lock);
 	cg_runlock(&pool->data_lock);
 	
 	
-	ssj->swork.data_lock_p = NULL;
+	if (clean)
+	{
+		struct stratumsrv_job *ssj, *tmp;
+		
+		applog(LOG_DEBUG, "SSM: Current replacing job stale, pruning all jobs");
+		HASH_ITER(hh, _ssm_jobs, ssj, tmp)
+		{
+			HASH_DEL(_ssm_jobs, ssj);
+			_ssj_free(ssj);
+		}
+	}
+	else
+		stratumsrv_job_pruner();
+	
 	HASH_ADD_KEYPTR(hh, _ssm_jobs, ssj->my_job_id, strlen(ssj->my_job_id), ssj);
 	HASH_ADD_KEYPTR(hh, _ssm_jobs, ssj->my_job_id, strlen(ssj->my_job_id), ssj);
 	
 	
 	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->swork, &ssj->tv_prepared, NULL, 0);
+	work2d_gen_dummy_work_for_stale_check(&_ssm_cur_job_work, &ssj->swork, &ssj->tv_prepared, NULL);
 	
 	
 	_ssm_notify_sz = p - buf;
 	_ssm_notify_sz = p - buf;
 	assert(_ssm_notify_sz <= bufsz);
 	assert(_ssm_notify_sz <= bufsz);
@@ -329,7 +389,6 @@ static
 void _stratumsrv_update_notify(evutil_socket_t fd, short what, __maybe_unused void *p)
 void _stratumsrv_update_notify(evutil_socket_t fd, short what, __maybe_unused void *p)
 {
 {
 	struct pool *pool = current_pool();
 	struct pool *pool = current_pool();
-	bool clean;
 	
 	
 	if (fd == _ssm_update_notifier[0])
 	if (fd == _ssm_update_notifier[0])
 	{
 	{
@@ -338,37 +397,8 @@ void _stratumsrv_update_notify(evutil_socket_t fd, short what, __maybe_unused vo
 		applog(LOG_DEBUG, "SSM: Update triggered by notifier");
 		applog(LOG_DEBUG, "SSM: Update triggered by notifier");
 	}
 	}
 	
 	
-	clean = _ssm_cur_job_work.pool ? stale_work(&_ssm_cur_job_work, true) : true;
-	if (clean)
-	{
-		struct stratumsrv_job *ssj, *tmp;
-		
-		applog(LOG_DEBUG, "SSM: Current replacing job stale, pruning all jobs");
-		HASH_ITER(hh, _ssm_jobs, ssj, tmp)
-		{
-			HASH_DEL(_ssm_jobs, ssj);
-			_ssj_free(ssj);
-		}
-	}
-	else
-		stratumsrv_job_pruner();
-	
-	if (!pool_has_usable_swork(pool))
-	{
-		applog(LOG_WARNING, "SSM: No usable 2D work upstream!");
-		if (clean)
-			stratumsrv_boot_all_subscribed("Current upstream pool does not have usable 2D work");
-		goto out;
-	}
-	
-	if (!stratumsrv_update_notify_str(pool, clean))
-	{
-		applog(LOG_WARNING, "SSM: Failed to subdivide upstream stratum notify!");
-		if (clean)
-			stratumsrv_boot_all_subscribed("Current upstream pool does not have active stratum");
-	}
+	stratumsrv_update_notify_str(pool);
 	
 	
-out: ;
 	struct timeval tv_scantime = {
 	struct timeval tv_scantime = {
 		.tv_sec = opt_scantime,
 		.tv_sec = opt_scantime,
 	};
 	};
@@ -789,32 +819,42 @@ void stratumlistener(struct evconnlistener *listener, evutil_socket_t sock, stru
 	bufferevent_enable(bev, EV_READ | EV_WRITE);
 	bufferevent_enable(bev, EV_READ | EV_WRITE);
 }
 }
 
 
-void stratumsrv_start();
+static bool stratumsrv_init_server(void);
 
 
-void stratumsrv_change_port()
+bool stratumsrv_change_port(const unsigned port)
 {
 {
-	struct event_base * const evbase = _smm_evbase;
-	
-	if (_smm_listener)
-		evconnlistener_free(_smm_listener);
-	
-	if (!_smm_running)
-	{
-		stratumsrv_start();
-		return;
+	if (!_smm_running) {
+		if (!stratumsrv_init_server()) {
+			return false;
+		}
 	}
 	}
 	
 	
+	struct event_base * const evbase = _smm_evbase;
+	struct evconnlistener * const old_smm_listener = _smm_listener;
+	
 	struct sockaddr_in sin = {
 	struct sockaddr_in sin = {
 		.sin_family = AF_INET,
 		.sin_family = AF_INET,
 		.sin_addr.s_addr = INADDR_ANY,
 		.sin_addr.s_addr = INADDR_ANY,
-		.sin_port = htons(stratumsrv_port),
+		.sin_port = htons(port),
 	};
 	};
 	_smm_listener = evconnlistener_new_bind(evbase, stratumlistener, NULL, (
 	_smm_listener = evconnlistener_new_bind(evbase, stratumlistener, NULL, (
 		LEV_OPT_CLOSE_ON_FREE | LEV_OPT_CLOSE_ON_EXEC | LEV_OPT_REUSEABLE
 		LEV_OPT_CLOSE_ON_FREE | LEV_OPT_CLOSE_ON_EXEC | LEV_OPT_REUSEABLE
 	), 0x10, (void*)&sin, sizeof(sin));
 	), 0x10, (void*)&sin, sizeof(sin));
 	
 	
+	if (!_smm_listener) {
+		applog(LOG_ERR, "SSM: Failed to listen on port %u", (unsigned)port);
+		return false;
+	}
+	
 	// NOTE: libevent doesn't seem to implement LEV_OPT_CLOSE_ON_EXEC for Windows, so we must do this ourselves
 	// NOTE: libevent doesn't seem to implement LEV_OPT_CLOSE_ON_EXEC for Windows, so we must do this ourselves
 	set_cloexec_socket(evconnlistener_get_fd(_smm_listener), true);
 	set_cloexec_socket(evconnlistener_get_fd(_smm_listener), true);
+	
+	if (old_smm_listener) {
+		evconnlistener_free(old_smm_listener);
+	}
+	stratumsrv_port = port;
+	
+	return true;
 }
 }
 
 
 static
 static
@@ -823,29 +863,59 @@ void *stratumsrv_thread(__maybe_unused void *p)
 	pthread_detach(pthread_self());
 	pthread_detach(pthread_self());
 	RenameThread("stratumsrv");
 	RenameThread("stratumsrv");
 	
 	
+	struct event_base *evbase = _smm_evbase;
+	event_base_dispatch(evbase);
+	_smm_running = false;
+	
+	return NULL;
+}
+
+static
+bool stratumsrv_init_server() {
 	work2d_init();
 	work2d_init();
 	
 	
+	if (-1
+#if EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED
+	 && evthread_use_windows_threads()
+#endif
+#if EVTHREAD_USE_PTHREADS_IMPLEMENTED
+	 && evthread_use_pthreads()
+#endif
+	) {
+		applog(LOG_ERR, "SSM: %s failed", "event_use_*threads");
+		return false;
+	}
+	
 	struct event_base *evbase = event_base_new();
 	struct event_base *evbase = event_base_new();
+	if (!evbase) {
+		applog(LOG_ERR, "SSM: %s failed", "event_base_new");
+		return false;
+	}
 	_smm_evbase = evbase;
 	_smm_evbase = evbase;
+	
 	{
 	{
 		ev_notify = evtimer_new(evbase, _stratumsrv_update_notify, NULL);
 		ev_notify = evtimer_new(evbase, _stratumsrv_update_notify, NULL);
+		if (!ev_notify) {
+			applog(LOG_ERR, "SSM: %s failed", "evtimer_new");
+			return false;
+		}
 		_stratumsrv_update_notify(-1, 0, NULL);
 		_stratumsrv_update_notify(-1, 0, NULL);
 	}
 	}
 	{
 	{
 		notifier_init(_ssm_update_notifier);
 		notifier_init(_ssm_update_notifier);
 		struct event *ev_update_notifier = event_new(evbase, _ssm_update_notifier[0], EV_READ | EV_PERSIST, _stratumsrv_update_notify, NULL);
 		struct event *ev_update_notifier = event_new(evbase, _ssm_update_notifier[0], EV_READ | EV_PERSIST, _stratumsrv_update_notify, NULL);
+		if (!ev_update_notifier) {
+			applog(LOG_ERR, "SSM: %s failed", "event_new");
+			return false;
+		}
 		event_add(ev_update_notifier, NULL);
 		event_add(ev_update_notifier, NULL);
 	}
 	}
-	stratumsrv_change_port();
-	event_base_dispatch(evbase);
 	
 	
-	return NULL;
-}
-
-void stratumsrv_start()
-{
 	_smm_running = true;
 	_smm_running = true;
+	
 	pthread_t pth;
 	pthread_t pth;
 	if (unlikely(pthread_create(&pth, NULL, stratumsrv_thread, NULL)))
 	if (unlikely(pthread_create(&pth, NULL, stratumsrv_thread, NULL)))
 		quit(1, "stratumsrv thread create failed");
 		quit(1, "stratumsrv thread create failed");
-}
+	
+	return true;
+}

+ 1 - 1
libblkmaker

@@ -1 +1 @@
-Subproject commit e9cd82be9352d502fce9df696a8933567e1e00a4
+Subproject commit d2dde7a9edd4ec0360b82dd70be5586163ac2fe8

+ 70 - 30
miner.c

@@ -1,6 +1,6 @@
 /*
 /*
  * Copyright 2011-2014 Con Kolivas
  * Copyright 2011-2014 Con Kolivas
- * Copyright 2011-2014 Luke Dashjr
+ * Copyright 2011-2016 Luke Dashjr
  * Copyright 2014 Nate Woolls
  * Copyright 2014 Nate Woolls
  * Copyright 2012-2014 Andrew Smith
  * Copyright 2012-2014 Andrew Smith
  * Copyright 2010 Jeff Garzik
  * Copyright 2010 Jeff Garzik
@@ -183,7 +183,7 @@ bool opt_restart = true;
 int httpsrv_port = -1;
 int httpsrv_port = -1;
 #endif
 #endif
 #ifdef USE_LIBEVENT
 #ifdef USE_LIBEVENT
-int stratumsrv_port = -1;
+long stratumsrv_port = -1;
 #endif
 #endif
 
 
 const
 const
@@ -1173,6 +1173,7 @@ struct pool *add_pool2(struct mining_goal_info * const goal)
 	if (unlikely(pthread_cond_init(&pool->cr_cond, bfg_condattr)))
 	if (unlikely(pthread_cond_init(&pool->cr_cond, bfg_condattr)))
 		quit(1, "Failed to pthread_cond_init in add_pool");
 		quit(1, "Failed to pthread_cond_init in add_pool");
 	cglock_init(&pool->data_lock);
 	cglock_init(&pool->data_lock);
+	pool->swork.data_lock_p = &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;
 	pool->swork.pool = pool;
@@ -1314,6 +1315,23 @@ static char *set_int_1_to_10(const char *arg, int *i)
 	return set_int_range(arg, i, 1, 10);
 	return set_int_range(arg, i, 1, 10);
 }
 }
 
 
+static char *set_long_1_to_65535_or_neg1(const char * const arg, long * const i)
+{
+	const long min = 1, max = 65535;
+	
+	char * const err = opt_set_longval(arg, i);
+	
+	if (err) {
+		return err;
+	}
+	
+	if (*i != -1 && (*i < min || *i > max)) {
+		return "Value out of range";
+	}
+	
+	return NULL;
+}
+
 char *set_strdup(const char *arg, char **p)
 char *set_strdup(const char *arg, char **p)
 {
 {
 	*p = strdup((char *)arg);
 	*p = strdup((char *)arg);
@@ -2714,7 +2732,7 @@ static struct opt_table opt_config_table[] = {
 		     "Set socks proxy (host:port)"),
 		     "Set socks proxy (host:port)"),
 #ifdef USE_LIBEVENT
 #ifdef USE_LIBEVENT
 	OPT_WITH_ARG("--stratum-port",
 	OPT_WITH_ARG("--stratum-port",
-	             opt_set_intval, opt_show_intval, &stratumsrv_port,
+	             set_long_1_to_65535_or_neg1, opt_show_longval, &stratumsrv_port,
 	             "Port number to listen on for stratum miners (-1 means disabled)"),
 	             "Port number to listen on for stratum miners (-1 means disabled)"),
 #endif
 #endif
 	OPT_WITHOUT_ARG("--submit-stale",
 	OPT_WITHOUT_ARG("--submit-stale",
@@ -3443,7 +3461,7 @@ void refresh_bitcoind_address(struct mining_goal_info * const goal, const bool f
 
 
 #define GBT_XNONCESZ (sizeof(uint32_t))
 #define GBT_XNONCESZ (sizeof(uint32_t))
 
 
-#if BLKMAKER_VERSION > 4
+#if BLKMAKER_VERSION > 6
 #define blkmk_append_coinbase_safe(tmpl, append, appendsz)  \
 #define blkmk_append_coinbase_safe(tmpl, append, appendsz)  \
        blkmk_append_coinbase_safe2(tmpl, append, appendsz, GBT_XNONCESZ, false)
        blkmk_append_coinbase_safe2(tmpl, append, appendsz, GBT_XNONCESZ, false)
 #endif
 #endif
@@ -3624,7 +3642,7 @@ static bool work_decode(struct pool *pool, struct work *work, json_t *val)
 
 
 	work->tv_staged = tv_now;
 	work->tv_staged = tv_now;
 	
 	
-#if BLKMAKER_VERSION > 4
+#if BLKMAKER_VERSION > 6
 	if (work->tr)
 	if (work->tr)
 	{
 	{
 		blktemplate_t * const tmpl = work->tr->tmpl;
 		blktemplate_t * const tmpl = work->tr->tmpl;
@@ -3644,15 +3662,18 @@ static bool work_decode(struct pool *pool, struct work *work, json_t *val)
 			pool_check_coinbase(pool, cbtxn, cbtxnsz);
 			pool_check_coinbase(pool, cbtxn, cbtxnsz);
 			
 			
 			cg_wlock(&pool->data_lock);
 			cg_wlock(&pool->data_lock);
+			if (swork->tr)
+				tmpl_decref(swork->tr);
 			swork->tr = work->tr;
 			swork->tr = work->tr;
+			tmpl_incref(swork->tr);
 			bytes_assimilate_raw(&swork->coinbase, cbtxn, cbtxnsz, cbtxnsz);
 			bytes_assimilate_raw(&swork->coinbase, cbtxn, cbtxnsz, cbtxnsz);
 			swork->nonce2_offset = cbextranonceoffset;
 			swork->nonce2_offset = cbextranonceoffset;
 			bytes_assimilate_raw(&swork->merkle_bin, branches, branchdatasz, branchdatasz);
 			bytes_assimilate_raw(&swork->merkle_bin, branches, branchdatasz, branchdatasz);
 			swork->merkles = branchcount;
 			swork->merkles = branchcount;
-			memcpy(swork->header1, &buf[0], 36);
+			swap32yes(swork->header1, &buf[0], 36 / 4);
 			swork->ntime = le32toh(*(uint32_t *)(&buf[68]));
 			swork->ntime = le32toh(*(uint32_t *)(&buf[68]));
 			swork->tv_received = tv_now;
 			swork->tv_received = tv_now;
-			memcpy(swork->diffbits, &buf[72], 4);
+			swap32yes(swork->diffbits, &buf[72], 4 / 4);
 			memcpy(swork->target, work->target, sizeof(swork->target));
 			memcpy(swork->target, work->target, sizeof(swork->target));
 			free(swork->job_id);
 			free(swork->job_id);
 			swork->job_id = NULL;
 			swork->job_id = NULL;
@@ -3666,7 +3687,7 @@ static bool work_decode(struct pool *pool, struct work *work, json_t *val)
 		else
 		else
 			applog(LOG_DEBUG, "blkmk_get_mdata failed for pool %u", pool->pool_no);
 			applog(LOG_DEBUG, "blkmk_get_mdata failed for pool %u", pool->pool_no);
 	}
 	}
-#endif  // BLKMAKER_VERSION > 4
+#endif  // BLKMAKER_VERSION > 6
 	pool_set_opaque(pool, !work->tr);
 	pool_set_opaque(pool, !work->tr);
 
 
 	ret = true;
 	ret = true;
@@ -5346,6 +5367,11 @@ static char *submit_upstream_work_request(struct work *work)
 		unsigned char data[80];
 		unsigned char data[80];
 		
 		
 		swap32yes(data, work->data, 80 / 4);
 		swap32yes(data, work->data, 80 / 4);
+#if BLKMAKER_VERSION > 6
+		if (work->stratum) {
+			req = blkmk_submitm_jansson(tmpl, data, bytes_buf(&work->nonce2), bytes_len(&work->nonce2), le32toh(*((uint32_t*)&work->data[76])), work->do_foreign_submit);
+		} else
+#endif
 #if BLKMAKER_VERSION > 3
 #if BLKMAKER_VERSION > 3
 		if (work->do_foreign_submit)
 		if (work->do_foreign_submit)
 			req = blkmk_submit_foreign_jansson(tmpl, data, work->dataid, le32toh(*((uint32_t*)&work->data[76])));
 			req = blkmk_submit_foreign_jansson(tmpl, data, work->dataid, le32toh(*((uint32_t*)&work->data[76])));
@@ -6780,7 +6806,7 @@ static struct submit_work_state *begin_submission(struct work *work)
 		timer_set_delay_from_now(&sws->tv_staleexpire, 300000000);
 		timer_set_delay_from_now(&sws->tv_staleexpire, 300000000);
 	}
 	}
 
 
-	if (work->stratum) {
+	if (work->getwork_mode == GETWORK_MODE_STRATUM) {
 		char *s;
 		char *s;
 
 
 		s = malloc(1024);
 		s = malloc(1024);
@@ -7940,7 +7966,7 @@ void write_config(FILE *fcfg)
 #endif
 #endif
 #ifdef USE_LIBEVENT
 #ifdef USE_LIBEVENT
 	if (stratumsrv_port != -1)
 	if (stratumsrv_port != -1)
-		fprintf(fcfg, ",\n\"stratum-port\" : %d", stratumsrv_port);
+		fprintf(fcfg, ",\n\"stratum-port\" : %ld", stratumsrv_port);
 #endif
 #endif
 	_write_config_string_elist(fcfg, "device", opt_devices_enabled_list);
 	_write_config_string_elist(fcfg, "device", opt_devices_enabled_list);
 	_write_config_string_elist(fcfg, "set-device", opt_set_device_list);
 	_write_config_string_elist(fcfg, "set-device", opt_set_device_list);
@@ -10264,6 +10290,7 @@ void stratum_work_cpy(struct stratum_work * const dst, const struct stratum_work
 	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);
+	dst->data_lock_p = NULL;
 }
 }
 
 
 void stratum_work_clean(struct stratum_work * const swork)
 void stratum_work_clean(struct stratum_work * const swork)
@@ -10298,7 +10325,6 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
 	clean_work(work);
 	clean_work(work);
 	
 	
 	cg_wlock(&pool->data_lock);
 	cg_wlock(&pool->data_lock);
-	pool->swork.data_lock_p = &pool->data_lock;
 	
 	
 	const int n2size = pool->swork.n2size;
 	const int n2size = pool->swork.n2size;
 	bytes_resize(&work->nonce2, n2size);
 	bytes_resize(&work->nonce2, n2size);
@@ -10323,11 +10349,8 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
 
 
 void gen_stratum_work2(struct work *work, struct stratum_work *swork)
 void gen_stratum_work2(struct work *work, struct stratum_work *swork)
 {
 {
-	unsigned char *coinbase, merkle_root[32], merkle_sha[64];
-	uint8_t *merkle_bin;
-	uint32_t *data32, *swap32;
-	int i;
-
+	unsigned char *coinbase;
+	
 	/* Generate coinbase */
 	/* Generate coinbase */
 	coinbase = bytes_buf(&swork->coinbase);
 	coinbase = bytes_buf(&swork->coinbase);
 	memcpy(&coinbase[swork->nonce2_offset], bytes_buf(&work->nonce2), bytes_len(&work->nonce2));
 	memcpy(&coinbase[swork->nonce2_offset], bytes_buf(&work->nonce2), bytes_len(&work->nonce2));
@@ -10335,7 +10358,29 @@ void gen_stratum_work2(struct work *work, struct stratum_work *swork)
 	/* Downgrade to a read lock to read off the variables */
 	/* Downgrade to a read lock to read off the variables */
 	if (swork->data_lock_p)
 	if (swork->data_lock_p)
 		cg_dwlock(swork->data_lock_p);
 		cg_dwlock(swork->data_lock_p);
+	
+	gen_stratum_work3(work, swork, swork->data_lock_p);
+	
+	if (opt_debug)
+	{
+		char header[161];
+		char nonce2hex[(bytes_len(&work->nonce2) * 2) + 1];
+		bin2hex(header, work->data, 80);
+		bin2hex(nonce2hex, 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);
+	}
+}
 
 
+void gen_stratum_work3(struct work * const work, struct stratum_work * const swork, cglock_t * const data_lock_p)
+{
+	unsigned char *coinbase, merkle_root[32], merkle_sha[64];
+	uint8_t *merkle_bin;
+	uint32_t *data32, *swap32;
+	int i;
+	
+	coinbase = bytes_buf(&swork->coinbase);
+	
 	/* Generate merkle root */
 	/* Generate merkle root */
 	gen_hash(coinbase, merkle_root, bytes_len(&swork->coinbase));
 	gen_hash(coinbase, merkle_root, bytes_len(&swork->coinbase));
 	memcpy(merkle_sha, merkle_root, 32);
 	memcpy(merkle_sha, merkle_root, 32);
@@ -10362,18 +10407,8 @@ void gen_stratum_work2(struct work *work, struct stratum_work *swork)
 	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(swork->nonce1);
 	work->nonce1 = maybe_strdup(swork->nonce1);
-	if (swork->data_lock_p)
-		cg_runlock(swork->data_lock_p);
-
-	if (opt_debug)
-	{
-		char header[161];
-		char nonce2hex[(bytes_len(&work->nonce2) * 2) + 1];
-		bin2hex(header, work->data, 80);
-		bin2hex(nonce2hex, 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);
-	}
+	if (data_lock_p)
+		cg_runlock(data_lock_p);
 
 
 	calc_midstate(work);
 	calc_midstate(work);
 
 
@@ -10383,6 +10418,11 @@ void gen_stratum_work2(struct work *work, struct stratum_work *swork)
 	work->id = total_work++;
 	work->id = total_work++;
 	work->longpoll = false;
 	work->longpoll = false;
 	work->getwork_mode = GETWORK_MODE_STRATUM;
 	work->getwork_mode = GETWORK_MODE_STRATUM;
+	if (swork->tr) {
+		work->getwork_mode = GETWORK_MODE_GBT;
+		work->tr = swork->tr;
+		tmpl_incref(work->tr);
+	}
 	calc_diff(work, 0);
 	calc_diff(work, 0);
 }
 }
 
 
@@ -13185,7 +13225,7 @@ void bfg_atexit(void)
 }
 }
 
 
 extern void bfg_init_threadlocal();
 extern void bfg_init_threadlocal();
-extern void stratumsrv_start();
+extern bool stratumsrv_change_port(unsigned);
 extern void test_aan_pll(void);
 extern void test_aan_pll(void);
 
 
 int main(int argc, char *argv[])
 int main(int argc, char *argv[])
@@ -13748,7 +13788,7 @@ begin_bench:
 
 
 #ifdef USE_LIBEVENT
 #ifdef USE_LIBEVENT
 	if (stratumsrv_port != -1)
 	if (stratumsrv_port != -1)
-		stratumsrv_start();
+		stratumsrv_change_port(stratumsrv_port);
 #endif
 #endif
 
 
 #ifdef HAVE_BFG_HOTPLUG
 #ifdef HAVE_BFG_HOTPLUG

+ 2 - 1
miner.h

@@ -985,7 +985,7 @@ extern int last_logstatusline_len;
 extern bool have_libusb;
 extern bool have_libusb;
 #endif
 #endif
 extern int httpsrv_port;
 extern int httpsrv_port;
-extern int stratumsrv_port;
+extern long stratumsrv_port;
 extern char *opt_api_allow;
 extern char *opt_api_allow;
 extern bool opt_api_mcast;
 extern bool opt_api_mcast;
 extern char *opt_api_mcast_addr;
 extern char *opt_api_mcast_addr;
@@ -1543,6 +1543,7 @@ extern void stratum_work_cpy(struct stratum_work *dst, const struct stratum_work
 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 *);
 extern void gen_stratum_work2(struct work *, struct stratum_work *);
+extern void gen_stratum_work3(struct work *, struct stratum_work *, cglock_t *data_lock_p);
 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)

+ 14 - 2
openwrt/bfgminer/Makefile

@@ -11,12 +11,16 @@ include $(TOPDIR)/rules.mk
 
 
 PKG_NAME:=bfgminer
 PKG_NAME:=bfgminer
 PKG_TITLE:=BFGMiner
 PKG_TITLE:=BFGMiner
-PKG_VERSION:=5.4.0
+PKG_VERSION:=5.4.2
 PKG_RELEASE:=1
 PKG_RELEASE:=1
 
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).txz
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).txz
 PKG_SOURCE_URL:=http://luke.dashjr.org/programs/bitcoin/files/$(PKG_NAME)/$(PKG_VERSION)/
 PKG_SOURCE_URL:=http://luke.dashjr.org/programs/bitcoin/files/$(PKG_NAME)/$(PKG_VERSION)/
 
 
+PKG_MAINTAINER:=Luke Dashjr <luke-jr+bfgminer@utopios.org>
+PKG_LICENSE:=GPL-3.0+
+PKG_LICENSE_FILES:=COPYING
+
 PKG_INSTALL:=1
 PKG_INSTALL:=1
 
 
 include $(INCLUDE_DIR)/package.mk
 include $(INCLUDE_DIR)/package.mk
@@ -59,9 +63,13 @@ config PACKAGE_$(PKG_NAME)_libmicrohttpd
 	depends on PACKAGE_$(PKG_NAME)
 	depends on PACKAGE_$(PKG_NAME)
 	default y
 	default y
 config PACKAGE_$(PKG_NAME)_libusb
 config PACKAGE_$(PKG_NAME)_libusb
-	bool "Build with libusb support (X6500 & ZTEX)"
+	bool "Build with libusb support (Cointerra, HashBuster Micro, Klondike, X6500 & ZTEX)"
 	depends on PACKAGE_$(PKG_NAME)
 	depends on PACKAGE_$(PKG_NAME)
 	default y
 	default y
+config PACKAGE_$(PKG_NAME)_bitmain
+	bool "Build with bitmain driver (only for S* series miners)"
+	depends on PACKAGE_$(PKG_NAME)
+	default n
 config PACKAGE_$(PKG_NAME)_keccak
 config PACKAGE_$(PKG_NAME)_keccak
 	bool "Build with Keccak algorithm support"
 	bool "Build with Keccak algorithm support"
 	depends on PACKAGE_$(PKG_NAME)
 	depends on PACKAGE_$(PKG_NAME)
@@ -94,6 +102,10 @@ ifndef CONFIG_PACKAGE_$(PKG_NAME)_libusb
 CONFIGURE_ARGS += --without-libusb
 CONFIGURE_ARGS += --without-libusb
 endif
 endif
 
 
+ifdef CONFIG_PACKAGE_$(PKG_NAME)_bitmain
+CONFIGURE_ARGS += --enable-bitmain
+endif
+
 ifdef CONFIG_PACKAGE_$(PKG_NAME)_keccak
 ifdef CONFIG_PACKAGE_$(PKG_NAME)_keccak
 CONFIGURE_ARGS += --enable-keccak
 CONFIGURE_ARGS += --enable-keccak
 endif
 endif

+ 17 - 6
openwrt/multibuild.sh

@@ -1,5 +1,5 @@
 #!/bin/bash
 #!/bin/bash
-# Copyright 2013 Luke Dashjr
+# Copyright 2013-2016 Luke Dashjr
 #
 #
 # This program is free software; you can redistribute it and/or modify it
 # This program is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by the Free
 # under the terms of the GNU General Public License as published by the Free
@@ -9,10 +9,13 @@
 set -e
 set -e
 set -x
 set -x
 reporoot="$1"  # .../files/bfgminer/BFGMINER_VERSION/openwrt/OPENWRT_VERSION
 reporoot="$1"  # .../files/bfgminer/BFGMINER_VERSION/openwrt/OPENWRT_VERSION
+openwrt_root="${2:-openwrt-src}"
+BITSTREAM_PKG_PATH="${3}"  # Relative to reporoot
 test -n "$reporoot"
 test -n "$reporoot"
 reporoot="$(realpath "$reporoot")"
 reporoot="$(realpath "$reporoot")"
 test -n "$reporoot"
 test -n "$reporoot"
-cd "openwrt-src/"
+cd "${openwrt_root}/"
+openwrt_root="$PWD"
 test -d "$reporoot"
 test -d "$reporoot"
 vcfgdir='vanilla_configs'
 vcfgdir='vanilla_configs'
 vcfglist="$(
 vcfglist="$(
@@ -20,7 +23,6 @@ vcfglist="$(
 	 perl -ple 's[.*/][]' |
 	 perl -ple 's[.*/][]' |
 	 sort -n
 	 sort -n
 )"
 )"
-BITSTREAM_PKG_PATH='../../../../bitstreams/openwrt/'  # Relative to reporoot
 BITSTREAMS=(
 BITSTREAMS=(
 	fpgaminer_402-1
 	fpgaminer_402-1
 	ztex-ufm1_15b1_121126-1
 	ztex-ufm1_15b1_121126-1
@@ -52,15 +54,24 @@ for cfn in $vcfglist; do
 	yes '' | make oldconfig
 	yes '' | make oldconfig
 	make {tools,toolchain}/install package/bfgminer/{clean,compile}
 	make {tools,toolchain}/install package/bfgminer/{clean,compile}
 	mkdir "$reporoot/$plat" -pv
 	mkdir "$reporoot/$plat" -pv
-	cp -v "bin/$plat/packages/"bfgminer*_${plat}.ipk "$reporoot/$plat/"
-	if [ -d "$reporoot/${BITSTREAM_PKG_PATH}" ]; then
+	files=$(ls "bin/$plat/packages/"{*/,}bfgminer*_${plat}*.ipk || true)
+	if test -z "${files}"; then
+		echo "Cannot find built packages"
+		exit 1
+	fi
+	cp -v ${files} "$reporoot/$plat/"
+	if [ -n "${BITSTREAM_PKG_PATH}" ]; then
 	(
 	(
+		test -d "$reporoot/${BITSTREAM_PKG_PATH}"
 		cd "$reporoot/$plat"
 		cd "$reporoot/$plat"
 		for bs in ${BITSTREAMS[@]}; do
 		for bs in ${BITSTREAMS[@]}; do
 			ln -vfs "../${BITSTREAM_PKG_PATH}/bitstream-${bs}_all.ipk" .
 			ln -vfs "../${BITSTREAM_PKG_PATH}/bitstream-${bs}_all.ipk" .
 		done
 		done
 	)
 	)
 	fi
 	fi
-	staging_dir/host/bin/ipkg-make-index "$reporoot/$plat/" > "$reporoot/$plat/Packages"
+	(
+		cd "$reporoot/$plat/"
+		"${openwrt_root}/scripts/ipkg-make-index.sh" .
+	) > "$reporoot/$plat/Packages"
 	gzip -9 < "$reporoot/$plat/Packages" > "$reporoot/$plat/Packages.gz"
 	gzip -9 < "$reporoot/$plat/Packages" > "$reporoot/$plat/Packages.gz"
 done
 done

+ 18 - 4
work2d.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2013-2014 Luke Dashjr
+ * Copyright 2013-2016 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
  * under the terms of the GNU General Public License as published by the Free
@@ -9,6 +9,7 @@
 
 
 #include "config.h"
 #include "config.h"
 
 
+#include <limits.h>
 #include <stdbool.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdint.h>
 #include <string.h>
 #include <string.h>
@@ -70,15 +71,21 @@ void *work2d_pad_xnonce(void * const buf_, const struct stratum_work * const swo
 	return &buf[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)
+static void work2d_gen_dummy_work_prepare(struct work * const work, struct stratum_work * const swork, const struct timeval * const tvp_prepared)
 {
 {
-	uint8_t *p, *s;
-	
 	*work = (struct work){
 	*work = (struct work){
 		.pool = swork->pool,
 		.pool = swork->pool,
 		.work_restart_id = swork->work_restart_id,
 		.work_restart_id = swork->work_restart_id,
 		.tv_staged = *tvp_prepared,
 		.tv_staged = *tvp_prepared,
 	};
 	};
+}
+
+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;
+	
+	work2d_gen_dummy_work_prepare(work, swork, tvp_prepared);
+	
 	bytes_resize(&work->nonce2, swork->n2size);
 	bytes_resize(&work->nonce2, swork->n2size);
 	s = bytes_buf(&work->nonce2);
 	s = bytes_buf(&work->nonce2);
 	p = &s[swork->n2size - work2d_xnonce2sz];
 	p = &s[swork->n2size - work2d_xnonce2sz];
@@ -94,6 +101,12 @@ void work2d_gen_dummy_work(struct work * const work, struct stratum_work * const
 	gen_stratum_work2(work, swork);
 	gen_stratum_work2(work, swork);
 }
 }
 
 
+void work2d_gen_dummy_work_for_stale_check(struct work * const work, struct stratum_work * const swork, const struct timeval * const tvp_prepared, cglock_t * const data_lock_p)
+{
+	work2d_gen_dummy_work_prepare(work, swork, tvp_prepared);
+	gen_stratum_work3(work, swork, data_lock_p);
+}
+
 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)
 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;
 	struct work _work, *work;
@@ -104,6 +117,7 @@ bool work2d_submit_nonce(struct thr_info * const thr, struct stratum_work * cons
 	work2d_gen_dummy_work(work, swork, tvp_prepared, xnonce2, xnonce1);
 	work2d_gen_dummy_work(work, swork, tvp_prepared, xnonce2, xnonce1);
 	*(uint32_t *)&work->data[68] = htobe32(ntime);
 	*(uint32_t *)&work->data[68] = htobe32(ntime);
 	work->nonce_diff = nonce_diff;
 	work->nonce_diff = nonce_diff;
+	work->rolltime = INT_MAX;  // FIXME
 	
 	
 	// Check if it's stale, if desired
 	// Check if it's stale, if desired
 	if (out_is_stale)
 	if (out_is_stale)

+ 1 - 0
work2d.h

@@ -16,6 +16,7 @@ extern void release_work2d_(uint32_t xnonce1);
 extern int work2d_pad_xnonce_size(const struct stratum_work *);
 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_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 void work2d_gen_dummy_work(struct work *, struct stratum_work *, const struct timeval *tvp_prepared, const void *xnonce2, uint32_t xnonce1);
+extern void work2d_gen_dummy_work_for_stale_check(struct work *, struct stratum_work *, const struct timeval *tvp_prepared, cglock_t *data_lock_p);
 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);
 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