diff --git a/src/datum_blocktemplates.c b/src/datum_blocktemplates.c index aacbd73..9c83fbd 100644 --- a/src/datum_blocktemplates.c +++ b/src/datum_blocktemplates.c @@ -88,6 +88,7 @@ T_DATUM_TEMPLATE_DATA *template_data = NULL; int next_template_index = 0; const char *datum_blocktemplates_error = NULL; +atomic_uint_fast64_t g_last_block_template_monotonic_secs = 0; int datum_template_init(void) { char *temp = NULL, *ptr = NULL; @@ -401,6 +402,7 @@ void *datum_gateway_template_thread(void *args) { T_DATUM_TEMPLATE_DATA *t; bool was_notified = false; int wnc = 0; + uint64_t fetch_start_time_monotonic; uint64_t last_block_change = 0; pthread_t pthread_datum_gateway_fallback_notifier; tcurl = curl_easy_init(); @@ -445,6 +447,7 @@ void *datum_gateway_template_thread(void *args) { // fetch latest template snprintf(gbt_req, sizeof(gbt_req), "{\"method\":\"getblocktemplate\",\"params\":[{\"rules\":[\"segwit\"]}],\"id\":%"PRIu64"}",(uint64_t)((uint64_t)time(NULL)<<(uint64_t)8)|(uint64_t)(i&255)); + fetch_start_time_monotonic = monotonic_time_seconds(); gbt = bitcoind_json_rpc_call(tcurl, &datum_config, gbt_req); if (!gbt) { @@ -462,6 +465,7 @@ void *datum_gateway_template_thread(void *args) { t = datum_gbt_parser(res_val); if (t) { + g_last_block_template_monotonic_secs = fetch_start_time_monotonic; datum_blocktemplates_error = NULL; DLOG_DEBUG("height: %lu / value: %"PRIu64, (unsigned long)t->height, t->coinbasevalue); DLOG_DEBUG("--- prevhash: %s", t->previousblockhash); diff --git a/src/datum_blocktemplates.h b/src/datum_blocktemplates.h index a9f0e18..237caed 100644 --- a/src/datum_blocktemplates.h +++ b/src/datum_blocktemplates.h @@ -36,6 +36,8 @@ #ifndef _DATUM_BLOCKTEMPLATE_H_ #define _DATUM_BLOCKTEMPLATE_H_ +#include + #ifndef uint64_t #include #endif @@ -187,6 +189,7 @@ typedef struct { } T_DATUM_TEMPLATE_DATA; extern const char *datum_blocktemplates_error; +extern atomic_uint_fast64_t g_last_block_template_monotonic_secs; int datum_template_init(void); T_DATUM_TEMPLATE_DATA *datum_gbt_parser(json_t *gbt); diff --git a/src/datum_conf.c b/src/datum_conf.c index 41bb586..5384e87 100644 --- a/src/datum_conf.c +++ b/src/datum_conf.c @@ -66,6 +66,8 @@ const T_DATUM_CONFIG_ITEM datum_config_options[] = { .required = true, .ptr = datum_config.bitcoind_rpcurl, .max_string_len = sizeof(datum_config.bitcoind_rpcurl) }, { .var_type = DATUM_CONF_INT, .category = "bitcoind", .name = "work_update_seconds", .description = "How many seconds between normal work updates? (5-120, 40 suggested)", .required = false, .ptr = &datum_config.bitcoind_work_update_seconds, .default_int = 40 }, + { .var_type = DATUM_CONF_INT, .category = "bitcoind", .name = "work_update_stale_limit", .description = "Disconnect miners if template hasn't been updated in how many seconds? (400-600 suggested)", + .required = false, .ptr = &datum_config.bitcoind_work_update_stale_limit, .default_int = 600 }, { .var_type = DATUM_CONF_BOOL, .category = "bitcoind", .name = "notify_fallback", .description = "Fall back to less efficient methods for new block notifications. Can disable if you use blocknotify.", .example_default = true, .required = false, .ptr = &datum_config.bitcoind_notify_fallback, .default_bool = true }, @@ -412,6 +414,11 @@ int datum_read_config(const char *conffile) { } #endif + if (datum_config.bitcoind_work_update_stale_limit < datum_config.bitcoind_work_update_seconds + 5) { + DLOG_FATAL("bitcoind work update stale limit must be at least the work update interval plus 5 seconds."); + return 0; + } + if (datum_config.stratum_v1_max_threads > MAX_THREADS) { DLOG_FATAL("Maximum threads must be less than %d.", MAX_THREADS); return 0; diff --git a/src/datum_conf.h b/src/datum_conf.h index 1bdc966..d7d1861 100644 --- a/src/datum_conf.h +++ b/src/datum_conf.h @@ -84,6 +84,7 @@ typedef struct { char bitcoind_rpcpassword[128]; char bitcoind_rpcurl[256]; int bitcoind_work_update_seconds; + int bitcoind_work_update_stale_limit; bool bitcoind_notify_fallback; char stratum_v1_listen_addr[128]; diff --git a/src/datum_gateway.c b/src/datum_gateway.c index cde5839..03bf7d4 100644 --- a/src/datum_gateway.c +++ b/src/datum_gateway.c @@ -140,6 +140,7 @@ int main(const int argc, const char * const * const argv) { struct sigaction sa; uint64_t last_datum_protocol_connect_tsms = 0; bool rejecting_stratum = false; + bool rejecting_stale_template = false; uint32_t next_reconnect_attempt_ms = 5000; // listen for block notifications @@ -253,6 +254,18 @@ int main(const int argc, const char * const * const argv) { } } + const uint64_t now_monotonic_secs = monotonic_time_seconds(); + + if (g_last_block_template_monotonic_secs + datum_config.bitcoind_work_update_stale_limit < now_monotonic_secs) { + if (!rejecting_stale_template) { + DLOG_ERROR("Failed to update block template in %d seconds! Shutting down Stratum v1 server until template updated.", (int)(now_monotonic_secs - g_last_block_template_monotonic_secs)); + rejecting_stale_template = true; + datum_stratum_v1_shutdown_all(); + } + } else { + rejecting_stale_template = false; + } + if (datum_config.datum_pooled_mining_only && (fail_retries >= 2) && (!datum_protocol_is_active())) { if (!rejecting_stratum) { DLOG_WARN("Configured for pooled mining only, and connection lost to DATUM server! Shutting down Stratum v1 server until DATUM connection reestablished."); diff --git a/src/datum_sockets.c b/src/datum_sockets.c index c0ca0e7..9b0d4d8 100644 --- a/src/datum_sockets.c +++ b/src/datum_sockets.c @@ -55,6 +55,7 @@ #include #include +#include "datum_blocktemplates.h" #include "datum_conf.h" #include "datum_gateway.h" #include "datum_protocol.h" @@ -646,6 +647,7 @@ void *datum_gateway_listener_thread(void *arg) { bool rejecting_now = false; uint64_t last_reject_msg_tsms = 0, curtime_tsms = 0; uint64_t reject_count = 0; + const char *reject_reason; T_DATUM_SOCKET_APP *app = (T_DATUM_SOCKET_APP *)arg; @@ -708,8 +710,15 @@ void *datum_gateway_listener_thread(void *arg) { for (;;) { nfds = epoll_wait(epollfd, events, MAX_EVENTS, 100); if (nfds) { + curtime_tsms = monotonic_time_seconds(); if (datum_config.datum_pooled_mining_only && (!datum_protocol_is_active())) { - curtime_tsms = current_time_millis(); // we only need this if we're rejecting connections + reject_reason = "DATUM not connected and configured for pooled mining only!"; + } else if (g_last_block_template_monotonic_secs + datum_config.bitcoind_work_update_stale_limit < curtime_tsms) { + reject_reason = "Failing to update block template!"; + } else { + reject_reason = NULL; + } + if (reject_reason) { if (!rejecting_now) { last_reject_msg_tsms = curtime_tsms - 5000; // first disconnect triggers msg } @@ -729,7 +738,7 @@ void *datum_gateway_listener_thread(void *arg) { if (rejecting_now) { reject_count++; if ((curtime_tsms - last_reject_msg_tsms) > 5000) { - DLOG_INFO("DATUM not connected and configured for pooled mining only! Rejecting connection. (%llu connections rejected since last noted)", (unsigned long long)reject_count); + DLOG_INFO("%s Rejecting connection. (%llu connections rejected since last noted)", reject_reason, (unsigned long long)reject_count); last_reject_msg_tsms = curtime_tsms; reject_count = 0; }