Browse Source

SSM: Implement mining.capabilities including proxying mining.set_goal

Luke Dashjr 11 years ago
parent
commit
20ababcee2
1 changed files with 96 additions and 22 deletions
  1. 96 22
      driver-stratum.c

+ 96 - 22
driver-stratum.c

@@ -35,8 +35,8 @@
 
 #define _ssm_client_octets     work2d_xnonce1sz
 #define _ssm_client_xnonce2sz  work2d_xnonce2sz
-static char *_ssm_notify;
-static int _ssm_notify_sz;
+static char *_ssm_notify, *_ssm_setgoal;
+static int _ssm_notify_sz, _ssm_setgoal_sz;
 static struct stratumsrv_job *_ssm_last_ssj;
 static struct event *ev_notify;
 static notifier_t _ssm_update_notifier;
@@ -66,8 +66,16 @@ struct stratumsrv_conn_userlist {
 	struct stratumsrv_conn_userlist *next;
 };
 
+enum stratumsrv_conn_capability {
+	SCC_NOTIFY    = 1 << 0,
+	SCC_SET_DIFF  = 1 << 1,
+	SCC_SET_GOAL  = 1 << 2,
+};
+typedef uint8_t stratumsrv_conn_capabilities_t;
+
 struct stratumsrv_conn {
 	struct bufferevent *bev;
+	stratumsrv_conn_capabilities_t capabilities;
 	uint32_t xnonce1_le;
 	struct timeval tv_hashes_done;
 	bool hashes_done_ext;
@@ -156,6 +164,10 @@ bool stratumsrv_update_notify_str(struct pool * const pool, bool clean)
 	bin2hex(ntime, &ntime_n, 4);
 	p += sprintf(p, "],\"%s\",\"%s\",\"%s\",%s],\"method\":\"mining.notify\",\"id\":null}\n", version, nbits, ntime, clean ? "true" : "false");
 	
+	const size_t setgoalbufsz = 49 + strlen(pool->goal->name) + (pool->goalname ? (1 + strlen(pool->goalname)) : 0) + 4 + 1;
+	char * const setgoalbuf = malloc(setgoalbufsz);
+	snprintf(setgoalbuf, setgoalbufsz, "{\"method\":\"mining.set_goal\",\"id\":null,\"params\":[\"%s%s%s\"]}\n", pool->goal->name, pool->goalname ? "/" : "", pool->goalname ?: "");
+	
 	ssj = malloc(sizeof(*ssj));
 	*ssj = (struct stratumsrv_job){
 		.my_job_id = strdup(my_job_id),
@@ -176,6 +188,15 @@ bool stratumsrv_update_notify_str(struct pool * const pool, bool clean)
 	assert(_ssm_notify_sz <= bufsz);
 	free(_ssm_notify);
 	_ssm_notify = buf;
+	const bool setgoal_changed = _ssm_setgoal ? strcmp(setgoalbuf, _ssm_setgoal) : true;
+	if (setgoal_changed)
+	{
+		free(_ssm_setgoal);
+		_ssm_setgoal = setgoalbuf;
+		_ssm_setgoal_sz = setgoalbufsz - 1;
+	}
+	else
+		free(setgoalbuf);
 	_ssm_last_ssj = ssj;
 	
 	float pdiff = target_diff(ssj->swork.target);
@@ -185,13 +206,19 @@ bool stratumsrv_update_notify_str(struct pool * const pool, bool clean)
 	{
 		if (unlikely(!conn->xnonce1_le))
 			continue;
-		float conn_pdiff = stratumsrv_choose_share_pdiff(conn, malgo);
-		if (pdiff < conn_pdiff)
-			conn_pdiff = pdiff;
-		ssj->job_pdiff[conn->xnonce1_le] = conn_pdiff;
-		if (conn_pdiff != conn->current_share_pdiff)
-			stratumsrv_send_set_difficulty(conn, conn_pdiff);
-		bufferevent_write(conn->bev, _ssm_notify, _ssm_notify_sz);
+		if (setgoal_changed && (conn->capabilities & SCC_SET_GOAL))
+			bufferevent_write(conn->bev, setgoalbuf, setgoalbufsz);
+		if (likely(conn->capabilities & SCC_SET_DIFF))
+		{
+			float conn_pdiff = stratumsrv_choose_share_pdiff(conn, malgo);
+			if (pdiff < conn_pdiff)
+				conn_pdiff = pdiff;
+			ssj->job_pdiff[conn->xnonce1_le] = conn_pdiff;
+			if (conn_pdiff != conn->current_share_pdiff)
+				stratumsrv_send_set_difficulty(conn, conn_pdiff);
+		}
+		if (likely(conn->capabilities & SCC_NOTIFY))
+			bufferevent_write(conn->bev, _ssm_notify, _ssm_notify_sz);
 	}
 	
 	return true;
@@ -388,18 +415,55 @@ void _stratumsrv_failure(struct bufferevent * const bev, const char * const idst
 }while(0)
 
 static
-void _stratumsrv_success(struct bufferevent * const bev, const char * const idstr)
+void stratumsrv_success2(struct bufferevent * const bev, const char * const idstr, const char * const resultstr)
 {
 	if (!idstr)
 		return;
 	
-	size_t bufsz = 36 + strlen(idstr);
+	size_t bufsz = 32 + strlen(resultstr) + strlen(idstr);
 	char buf[bufsz];
 	
-	bufsz = sprintf(buf, "{\"result\":true,\"id\":%s,\"error\":null}\n", idstr);
+	bufsz = sprintf(buf, "{\"result\":%s,\"id\":%s,\"error\":null}\n", resultstr, idstr);
 	bufferevent_write(bev, buf, bufsz);
 }
 
+static inline
+void _stratumsrv_success(struct bufferevent * const bev, const char * const idstr)
+{
+	stratumsrv_success2(bev, idstr, "true");
+}
+
+static
+void stratumsrv_mining_capabilities(struct bufferevent * const bev, json_t * const params, const char * const idstr, struct stratumsrv_conn * const conn)
+{
+	if (json_is_null(params) || (!json_is_array(params)))
+		return_stratumsrv_failure(20, "Bad params");
+	
+	conn->capabilities = 0;
+	
+	json_t * const caps = (json_array_size(params) < 1) ? NULL : json_array_get(params, 0);
+	if (caps && (!json_is_null(caps)) && json_is_array(caps))
+	{
+		for (size_t i = json_array_size(caps); i-- > 0; )
+		{
+			json_t * const j = json_array_get(caps, i);
+			if (!json_is_string(j))
+				continue;
+			const char * const s = json_string_value(j);
+			if (!strcasecmp(s, "notify"))
+				conn->capabilities |= SCC_NOTIFY;
+			else
+			if (!strcasecmp(s, "set_difficulty"))
+				conn->capabilities |= SCC_SET_DIFF;
+			else
+			if (!strcasecmp(s, "set_goal"))
+				conn->capabilities |= SCC_SET_GOAL;
+		}
+	}
+	
+	stratumsrv_success2(bev, idstr, "null");
+}
+
 static
 void stratumsrv_mining_subscribe(struct bufferevent * const bev, json_t * const params, const char * const idstr, struct stratumsrv_conn * const conn)
 {
@@ -426,16 +490,22 @@ void stratumsrv_mining_subscribe(struct bufferevent * const bev, json_t * const
 	bufsz = sprintf(buf, "{\"id\":%s,\"result\":[[[\"mining.set_difficulty\",\"x\"],[\"mining.notify\",\"%s\"]],\"%s\",%d],\"error\":null}\n", idstr, xnonce1x, xnonce1x, _ssm_client_xnonce2sz);
 	bufferevent_write(bev, buf, bufsz);
 	
-	const struct pool * const pool = _ssm_last_ssj->swork.pool;
-	const struct mining_goal_info * const goal = pool->goal;
-	const struct mining_algorithm * const malgo = goal->malgo;
-	float pdiff = target_diff(_ssm_last_ssj->swork.target);
-	const float conn_pdiff = stratumsrv_choose_share_pdiff(conn, malgo);
-	if (pdiff > conn_pdiff)
-		pdiff = conn_pdiff;
-	_ssm_last_ssj->job_pdiff[*xnonce1_p] = pdiff;
-	stratumsrv_send_set_difficulty(conn, pdiff);
-	bufferevent_write(bev, _ssm_notify, _ssm_notify_sz);
+	if (conn->capabilities & SCC_SET_GOAL)
+		bufferevent_write(conn->bev, _ssm_setgoal, _ssm_setgoal_sz);
+	if (likely(conn->capabilities & SCC_SET_DIFF))
+	{
+		const struct pool * const pool = _ssm_last_ssj->swork.pool;
+		const struct mining_goal_info * const goal = pool->goal;
+		const struct mining_algorithm * const malgo = goal->malgo;
+		float pdiff = target_diff(_ssm_last_ssj->swork.target);
+		const float conn_pdiff = stratumsrv_choose_share_pdiff(conn, malgo);
+		if (pdiff > conn_pdiff)
+			pdiff = conn_pdiff;
+		_ssm_last_ssj->job_pdiff[*xnonce1_p] = pdiff;
+		stratumsrv_send_set_difficulty(conn, pdiff);
+	}
+	if (likely(conn->capabilities & SCC_NOTIFY))
+		bufferevent_write(bev, _ssm_notify, _ssm_notify_sz);
 }
 
 static
@@ -619,6 +689,9 @@ errout:
 	else
 	if (!strcasecmp(method, "mining.subscribe"))
 		stratumsrv_mining_subscribe(bev, params, idstr, conn);
+	else
+	if (!strcasecmp(method, "mining.capabilities"))
+		stratumsrv_mining_capabilities(bev, params, idstr, conn);
 	else
 		_stratumsrv_failure(bev, idstr, -3, "Method not supported");
 	
@@ -709,6 +782,7 @@ void stratumlistener(struct evconnlistener *listener, evutil_socket_t sock, stru
 	conn = malloc(sizeof(*conn));
 	*conn = (struct stratumsrv_conn){
 		.bev = bev,
+		.capabilities = SCC_NOTIFY | SCC_SET_DIFF,
 		.desired_share_pdiff = FLT_MAX,
 		.desired_default_share_pdiff = true,
 	};