getblocktemplate: long polling

This commit is contained in:
pooler 2014-05-05 23:58:23 +02:00
parent 106d03882e
commit 8a8e0ad81c
2 changed files with 43 additions and 10 deletions

View file

@ -120,7 +120,6 @@ bool have_gbt = true;
bool allow_getwork = true; bool allow_getwork = true;
bool want_stratum = true; bool want_stratum = true;
bool have_stratum = false; bool have_stratum = false;
static bool submit_old = false;
bool use_syslog = false; bool use_syslog = false;
static bool opt_background = false; static bool opt_background = false;
static bool opt_quiet = false; static bool opt_quiet = false;
@ -186,7 +185,7 @@ Options:\n\
-s, --scantime=N upper bound on time spent scanning current work when\n\ -s, --scantime=N upper bound on time spent scanning current work when\n\
long polling is unavailable, in seconds (default: 5)\n\ long polling is unavailable, in seconds (default: 5)\n\
--coinbase-addr=ADDR payout address for solo mining\n\ --coinbase-addr=ADDR payout address for solo mining\n\
--no-longpoll disable X-Long-Polling support\n\ --no-longpoll disable long polling support\n\
--no-getwork disable getwork support\n\ --no-getwork disable getwork support\n\
--no-gbt disable getblocktemplate support\n\ --no-gbt disable getblocktemplate support\n\
--no-stratum disable X-Stratum support\n\ --no-stratum disable X-Stratum support\n\
@ -269,6 +268,8 @@ struct work {
static struct work g_work; static struct work g_work;
static time_t g_work_time; static time_t g_work_time;
static pthread_mutex_t g_work_lock; static pthread_mutex_t g_work_lock;
static bool submit_old = false;
static char *lp_id;
static inline void work_free(struct work *w) static inline void work_free(struct work *w)
{ {
@ -541,6 +542,20 @@ static bool gbt_work_decode(const json_t *val, struct work *work)
work->workid = strdup(json_string_value(tmp)); work->workid = strdup(json_string_value(tmp));
} }
/* Long polling */
tmp = json_object_get(val, "longpollid");
if (want_longpoll && json_is_string(tmp)) {
free(lp_id);
lp_id = strdup(json_string_value(tmp));
if (!have_longpoll) {
char *lp_uri;
tmp = json_object_get(val, "longpolluri");
lp_uri = json_is_string(tmp) ? strdup(json_string_value(tmp)) : rpc_url;
have_longpoll = true;
tq_push(thr_info[longpoll_thr_id].q, lp_uri);
}
}
rc = true; rc = true;
out: out:
@ -690,9 +705,14 @@ out:
static const char *getwork_req = static const char *getwork_req =
"{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n"; "{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n";
#define GBT_CAPABILITIES "[\"coinbasetxn\", \"coinbasevalue\", \"longpoll\", \"workid\"]"
static const char *gbt_req = static const char *gbt_req =
"{\"method\": \"getblocktemplate\", \"params\": [{\"capabilities\":" "{\"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": "
" [\"coinbasetxn\", \"coinbasevalue\", \"workid\"]}], \"id\":0}\r\n"; GBT_CAPABILITIES "}], \"id\":0}\r\n";
static const char *gbt_lp_req =
"{\"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": "
GBT_CAPABILITIES ", \"longpollid\": \"%s\"}], \"id\":0}\r\n";
static bool get_upstream_work(CURL *curl, struct work *work) static bool get_upstream_work(CURL *curl, struct work *work)
{ {
@ -1170,22 +1190,35 @@ start:
applog(LOG_INFO, "Long-polling activated for %s", lp_url); applog(LOG_INFO, "Long-polling activated for %s", lp_url);
while (1) { while (1) {
json_t *val, *soval; json_t *val, *res, *soval;
char *req = NULL;
int err; int err;
val = json_rpc_call(curl, lp_url, rpc_userpass, getwork_req, &err, if (have_gbt) {
req = malloc(strlen(gbt_lp_req) + strlen(lp_id) + 1);
sprintf(req, gbt_lp_req, lp_id);
}
val = json_rpc_call(curl, lp_url, rpc_userpass,
req ? req : getwork_req, &err,
JSON_RPC_LONGPOLL); JSON_RPC_LONGPOLL);
free(req);
if (have_stratum) { if (have_stratum) {
if (val) if (val)
json_decref(val); json_decref(val);
goto out; goto out;
} }
if (likely(val)) { if (likely(val)) {
bool rc;
applog(LOG_INFO, "LONGPOLL detected new block"); applog(LOG_INFO, "LONGPOLL detected new block");
soval = json_object_get(json_object_get(val, "result"), "submitold"); res = json_object_get(val, "result");
soval = json_object_get(res, "submitold");
submit_old = soval ? json_is_true(soval) : false; submit_old = soval ? json_is_true(soval) : false;
pthread_mutex_lock(&g_work_lock); pthread_mutex_lock(&g_work_lock);
if (work_decode(json_object_get(val, "result"), &g_work)) { if (have_gbt)
rc = gbt_work_decode(res, &g_work);
else
rc = work_decode(res, &g_work);
if (rc) {
if (opt_debug) if (opt_debug)
applog(LOG_DEBUG, "DEBUG: got new work"); applog(LOG_DEBUG, "DEBUG: got new work");
time(&g_work_time); time(&g_work_time);

View file

@ -14,8 +14,8 @@ In its normal mode of operation, \fBminerd\fR connects to a mining server
(specified with the \fB\-o\fR option), receives work from it and starts hashing. (specified with the \fB\-o\fR option), receives work from it and starts hashing.
As soon as a solution is found, it is submitted to the same mining server, As soon as a solution is found, it is submitted to the same mining server,
which can accept or reject it. which can accept or reject it.
When using the getwork protocol, \fBminerd\fR can take advantage When using getwork or getblocktemplate,
of the long polling extension, if the server supports it; \fBminerd\fR can take advantage of long polling, if the server supports it;
in any case, fresh work is fetched as needed. in any case, fresh work is fetched as needed.
When using the Stratum protocol this is not possible, When using the Stratum protocol this is not possible,
and the server is responsible for sending fresh work at least every minute; and the server is responsible for sending fresh work at least every minute;