From 5c52cc65c7db87a2cebca87d2818fcc1b230984d Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 14 Sep 2014 14:52:07 +1000 Subject: [PATCH 1/3] Add an optional field notify per btcd that tells ckpool not to pool for block changes --- README | 4 +++- ckpool.conf | 8 +++++--- src/ckpool.c | 21 ++++++++++++++++++--- src/ckpool.h | 2 ++ src/generator.c | 17 +++++++++++------ src/stratifier.c | 4 +++- 6 files changed, 42 insertions(+), 14 deletions(-) diff --git a/README b/README index 580c1635..43eabf62 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. 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..e17e908d 100644 --- a/src/generator.c +++ b/src/generator.c @@ -299,10 +299,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 +313,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)) { @@ -1497,6 +1501,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); 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 From f124c5d5b56bbeeab76fd4e65f9a36adb417f9bf Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 14 Sep 2014 14:57:12 +1000 Subject: [PATCH 2/3] Readme update --- README | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README b/README index 43eabf62..d57a34ca 100644 --- a/README +++ b/README @@ -232,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 From d46609275ec954728636e6895f7c1e78d83c4a2f Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 14 Sep 2014 21:36:05 +1000 Subject: [PATCH 3/3] Implement fallback to higher priority server by using a ckmsgq to inform a server watchdog thread of what the current server is and testing if they're alive no more than every 5 seconds --- src/generator.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/generator.c b/src/generator.c index e17e908d..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)) { @@ -344,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")) { @@ -1464,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")) { @@ -1617,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; @@ -1624,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