diff --git a/README b/README index 580c1635..d57a34ca 100644 --- a/README +++ b/README @@ -219,7 +219,9 @@ The options recognised are as follows: "btcd" : This is an array of bitcoind(s) with the options url, auth and pass -which match the configured bitcoind. This is mandatory in pool mode. +which match the configured bitcoind. This is mandatory in pool mode. The +optional boolean field notify tells ckpool this btcd is using the notifier +and does not need to be polled for block changes. "proxy" : This is an array in the same format as btcd above but is used in proxy and passthrough mode to set the upstream pool and is mandatory. @@ -230,8 +232,9 @@ proxy and passthrough mode to set the upstream pool and is mandatory. blocks. "blockpoll" : This is the frequency in milliseconds for how often to check for -new network blocks and is 5000 by default. It is intended to be a backup only -for when the notifier is not set up or a sanity check for it. +new network blocks and is 100 by default. It is intended to be a backup only +for when the notifier is not set up and only polls if the "notify" field is +not set on a btcd. "update_interval" : This is the frequency that stratum updates are sent out to miners and is set to 30 seconds by default to help perpetuate transactions for diff --git a/ckpool.conf b/ckpool.conf index c3b8662b..62424d30 100644 --- a/ckpool.conf +++ b/ckpool.conf @@ -3,17 +3,19 @@ { "url" : "localhost:8332", "auth" : "user", - "pass" : "pass" + "pass" : "pass", + "notify" : true }, { "url" : "backup:8332", "auth" : "user", - "pass" : "pass" + "pass" : "pass", + "notify" : false } ], "btcaddress" : "14BMjogz69qe8hk9thyzbmR5pg34mVKB1e", "btcsig" : "/mined by ck/", -"blockpoll" : 5000, +"blockpoll" : 100, "update_interval" : 30, "serverurl" : "ckpool.org:3333", "mindiff" : 1, diff --git a/src/ckpool.c b/src/ckpool.c index 2146d658..4b384464 100644 --- a/src/ckpool.c +++ b/src/ckpool.c @@ -888,6 +888,21 @@ static void json_get_int(int *store, json_t *val, const char *res) *store = json_integer_value(entry); } +static void json_get_bool(bool *store, json_t *val, const char *res) +{ + json_t *entry = json_object_get(val, res); + + if (!entry) { + LOGDEBUG("Json did not find entry %s", res); + return; + } + if (!json_is_boolean(entry)) { + LOGWARNING("Json entry %s is not a boolean", res); + return; + } + *store = json_is_true(entry); +} + static void parse_btcds(ckpool_t *ckp, json_t *arr_val, int arr_size) { json_t *val; @@ -897,11 +912,13 @@ static void parse_btcds(ckpool_t *ckp, json_t *arr_val, int arr_size) ckp->btcdurl = ckzalloc(sizeof(char *) * arr_size); ckp->btcdauth = ckzalloc(sizeof(char *) * arr_size); ckp->btcdpass = ckzalloc(sizeof(char *) * arr_size); + ckp->btcdnotify = ckzalloc(sizeof(bool *) * arr_size); for (i = 0; i < arr_size; i++) { val = json_array_get(arr_val, i); json_get_string(&ckp->btcdurl[i], val, "url"); json_get_string(&ckp->btcdauth[i], val, "auth"); json_get_string(&ckp->btcdpass[i], val, "pass"); + json_get_bool(&ckp->btcdnotify[i], val, "notify"); } } @@ -1207,10 +1224,8 @@ int main(int argc, char **argv) ckp.donaddress = "14BMjogz69qe8hk9thyzbmR5pg34mVKB1e"; if (!ckp.btcaddress) ckp.btcaddress = ckp.donaddress; - /* Default blockpoll is sanity check only when notifier is not used or - * fails */ if (!ckp.blockpoll) - ckp.blockpoll = 5000; + ckp.blockpoll = 100; if (!ckp.update_interval) ckp.update_interval = 30; if (!ckp.mindiff) diff --git a/src/ckpool.h b/src/ckpool.h index b1cd43fa..16a2f998 100644 --- a/src/ckpool.h +++ b/src/ckpool.h @@ -71,6 +71,7 @@ struct server_instance { char *url; char *auth; char *pass; + bool notify; connsock_t cs; void *data; // Private data @@ -143,6 +144,7 @@ struct ckpool_instance { char **btcdurl; char **btcdauth; char **btcdpass; + bool *btcdnotify; int blockpoll; // How frequently in ms to poll bitcoind for block updates /* Difficulty settings */ diff --git a/src/generator.c b/src/generator.c index b119857b..50757137 100644 --- a/src/generator.c +++ b/src/generator.c @@ -122,6 +122,8 @@ struct proxy_instance { typedef struct proxy_instance proxy_instance_t; +static ckmsgq_t *srvchk; // Server check message queue + static bool server_alive(ckpool_t *ckp, server_instance_t *si, bool pinging) { char *userpass = NULL; @@ -252,6 +254,8 @@ reconnect: } retry: + ckmsgq_add(srvchk, si); + do { selret = wait_read_select(us->sockd, 5); if (!selret && !ping_main(ckp)) { @@ -299,10 +303,12 @@ retry: clear_gbtbase(gbt); } } else if (cmdmatch(buf, "getbest")) { - if (!get_bestblockhash(cs, hash)) { + if (si->notify) + send_unix_msg(sockd, "notify"); + else if (!get_bestblockhash(cs, hash)) { LOGINFO("No best block hash support from %s:%s", cs->url, cs->port); - send_unix_msg(sockd, "Failed"); + send_unix_msg(sockd, "failed"); } else { if (unlikely(!started)) { started = true; @@ -311,15 +317,17 @@ retry: send_unix_msg(sockd, hash); } } else if (cmdmatch(buf, "getlast")) { - int height = get_blockcount(cs); + int height; - if (height == -1) { - send_unix_msg(sockd, "Failed"); + if (si->notify) + send_unix_msg(sockd, "notify"); + else if ((height = get_blockcount(cs)) == -1) { + send_unix_msg(sockd, "failed"); goto reconnect; } else { LOGDEBUG("Height: %d", height); if (!get_blockhash(cs, height, hash)) { - send_unix_msg(sockd, "Failed"); + send_unix_msg(sockd, "failed"); goto reconnect; } else { if (unlikely(!started)) { @@ -340,6 +348,8 @@ retry: send_unix_msg(sockd, "true"); else send_unix_msg(sockd, "false"); + } else if (cmdmatch(buf, "fallback")) { + goto reconnect; } else if (cmdmatch(buf, "loglevel")) { sscanf(buf, "loglevel=%d", &ckp->loglevel); } else if (cmdmatch(buf, "ping")) { @@ -1460,6 +1470,8 @@ retry: LOGWARNING("Block rejected locally."); } else LOGNOTICE("No backup btcd to send block to ourselves"); + } else if (cmdmatch(buf, "fallback")) { + goto reconnect; } else if (cmdmatch(buf, "loglevel")) { sscanf(buf, "loglevel=%d", &ckp->loglevel); } else if (cmdmatch(buf, "ping")) { @@ -1497,6 +1509,7 @@ static int server_mode(ckpool_t *ckp, proc_instance_t *pi) si->url = ckp->btcdurl[i]; si->auth = ckp->btcdauth[i]; si->pass = ckp->btcdpass[i]; + si->notify = ckp->btcdnotify[i]; } ret = gen_loop(pi); @@ -1612,6 +1625,51 @@ static int proxy_mode(ckpool_t *ckp, proc_instance_t *pi) return ret; } +/* Tell the watchdog what the current server instance is and decide if we + * should check to see if the higher priority servers are alive and fallback */ +static void server_watchdog(ckpool_t *ckp, server_instance_t *cursi) +{ + static time_t last_t = 0; + bool alive = false; + time_t now_t; + int i, srvs; + + /* Rate limit to checking only once every 5 seconds */ + now_t = time(NULL); + if (now_t <= last_t + 5) + return; + + last_t = now_t; + + /* Is this the highest priority server already? */ + if (cursi == ckp->servers[0]) + return; + + if (ckp->proxy) + srvs = ckp->proxies; + else + srvs = ckp->btcds; + for (i = 0; i < srvs; i++) { + server_instance_t *si = ckp->servers[i]; + + /* Have we reached the current server? */ + if (si == cursi) + return; + + if (ckp->proxy) { + proxy_instance_t *proxi = si->data; + connsock_t *cs = proxi->cs; + + alive = proxy_alive(ckp, si, proxi, cs, true); + } else + alive = server_alive(ckp, si, true); + if (alive) + break; + } + if (alive) + send_proc(ckp->generator, "fallback"); +} + int generator(proc_instance_t *pi) { ckpool_t *ckp = pi->ckp; @@ -1619,6 +1677,8 @@ int generator(proc_instance_t *pi) LOGWARNING("%s generator starting", ckp->name); + srvchk = create_ckmsgq(ckp, "srvchk", &server_watchdog); + if (ckp->proxy) ret = proxy_mode(ckp, pi); else diff --git a/src/stratifier.c b/src/stratifier.c index 779c3d05..67863df0 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -1211,7 +1211,9 @@ static void *blockupdate(void *arg) while (42) { dealloc(buf); buf = send_recv_generator(ckp, request, GEN_LAX); - if (buf && strcmp(buf, lastswaphash) && !cmdmatch(buf, "failed")) { + if (buf && cmdmatch(buf, "notify")) + cksleep_ms(5000); + else if (buf && strcmp(buf, lastswaphash) && !cmdmatch(buf, "failed")) { LOGNOTICE("Block hash changed to %s", buf); update_base(ckp, GEN_PRIORITY); } else