diff --git a/configure.ac b/configure.ac index a2860eb0..7a509c70 100644 --- a/configure.ac +++ b/configure.ac @@ -34,7 +34,7 @@ PKG_PROG_PKG_CONFIG() AC_CHECK_HEADERS(stdio.h stdlib.h fcntl.h sys/time.h unistd.h) AC_CHECK_HEADERS(ctype.h errno.h byteswap.h string.h time.h) AC_CHECK_HEADERS(endian.h sys/endian.h arpa/inet.h) -AC_CHECK_HEADERS(alloca.h pthread.h stdio.h) +AC_CHECK_HEADERS(alloca.h pthread.h stdio.h math.h) AC_CHECK_HEADERS(sys/types.h sys/socket.h) AC_CHECK_HEADERS(stdint.h netinet/in.h netinet/tcp.h) diff --git a/src/libckpool.c b/src/libckpool.c index 493f2198..2fb53253 100644 --- a/src/libckpool.c +++ b/src/libckpool.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "ckpool.h" #include "libckpool.h" @@ -570,3 +571,172 @@ double tvdiff(tv_t *end, tv_t *start) { return end->tv_sec - start->tv_sec + (end->tv_usec - start->tv_usec) / 1000000.0; } + +/* Create an exponentially decaying average over interval */ +void decay_time(double *f, double fadd, double fsecs, double interval) +{ + double ftotal, fprop; + + if (fsecs <= 0) + return; + fprop = 1.0 - 1 / (exp(fsecs / interval)); + ftotal = 1.0 + fprop; + *f += (fadd / fsecs * fprop); + *f /= ftotal; +} + +/* Convert a double value into a truncated string for displaying with its + * associated suitable for Mega, Giga etc. Buf array needs to be long enough */ +void suffix_string(double val, char *buf, size_t bufsiz, int sigdigits) +{ + const double kilo = 1000; + const double mega = 1000000; + const double giga = 1000000000; + const double tera = 1000000000000; + const double peta = 1000000000000000; + const double exa = 1000000000000000000; + char suffix[2] = ""; + bool decimal = true; + double dval; + + if (val >= exa) { + val /= peta; + dval = val / kilo; + strcpy(suffix, "E"); + } else if (val >= peta) { + val /= tera; + dval = val / kilo; + strcpy(suffix, "P"); + } else if (val >= tera) { + val /= giga; + dval = val / kilo; + strcpy(suffix, "T"); + } else if (val >= giga) { + val /= mega; + dval = val / kilo; + strcpy(suffix, "G"); + } else if (val >= mega) { + val /= kilo; + dval = val / kilo; + strcpy(suffix, "M"); + } else if (val >= kilo) { + dval = val / kilo; + strcpy(suffix, "K"); + } else { + dval = val; + decimal = false; + } + + if (!sigdigits) { + if (decimal) + snprintf(buf, bufsiz, "%.3g%s", dval, suffix); + else + snprintf(buf, bufsiz, "%d%s", (unsigned int)dval, suffix); + } else { + /* Always show sigdigits + 1, padded on right with zeroes + * followed by suffix */ + int ndigits = sigdigits - 1 - (dval > 0.0 ? floor(log10(dval)) : 0); + + snprintf(buf, bufsiz, "%*.*f%s", sigdigits + 1, ndigits, dval, suffix); + } +} + +/* truediffone == 0x00000000FFFF0000000000000000000000000000000000000000000000000000 + * Generate a 256 bit binary LE target by cutting up diff into 64 bit sized + * portions or vice versa. */ +static const double truediffone = 26959535291011309493156476344723991336010898738574164086137773096960.0; +static const double bits192 = 6277101735386680763835789423207666416102355444464034512896.0; +static const double bits128 = 340282366920938463463374607431768211456.0; +static const double bits64 = 18446744073709551616.0; + +/* Converts a little endian 256 bit value to a double */ +double le256todouble(const uchar *target) +{ + uint64_t *data64; + double dcut64; + + data64 = (uint64_t *)(target + 24); + dcut64 = le64toh(*data64) * bits192; + + data64 = (uint64_t *)(target + 16); + dcut64 += le64toh(*data64) * bits128; + + data64 = (uint64_t *)(target + 8); + dcut64 += le64toh(*data64) * bits64; + + data64 = (uint64_t *)(target); + dcut64 += le64toh(*data64); + + return dcut64; +} + +/* Return a difficulty from a binary target */ +double diff_from_target(uchar *target) +{ + double d64, dcut64; + + d64 = truediffone; + dcut64 = le256todouble(target); + if (unlikely(!dcut64)) + dcut64 = 1; + return d64 / dcut64; +} + +/* Return the network difficulty from the block header which is in packed form, + * as a double. */ +double diff_from_header(uchar *header) +{ + double numerator; + uint32_t diff32; + uint8_t pow; + int powdiff; + + pow = header[72]; + powdiff = (8 * (0x1d - 3)) - (8 * (pow - 3)); + diff32 = be32toh(*((uint32_t *)(header + 72))) & 0x00FFFFFF; + numerator = 0xFFFFULL << powdiff; + return numerator / (double)diff32; +} + +void target_from_diff(uchar *target, double diff) +{ + uint64_t *data64, h64; + double d64, dcut64; + + if (unlikely(diff == 0.0)) { + /* This shouldn't happen but best we check to prevent a crash */ + memset(target, 0, 32); + return; + } + + d64 = truediffone; + d64 /= diff; + + dcut64 = d64 / bits192; + h64 = dcut64; + data64 = (uint64_t *)(target + 24); + *data64 = htole64(h64); + dcut64 = h64; + dcut64 *= bits192; + d64 -= dcut64; + + dcut64 = d64 / bits128; + h64 = dcut64; + data64 = (uint64_t *)(target + 16); + *data64 = htole64(h64); + dcut64 = h64; + dcut64 *= bits128; + d64 -= dcut64; + + dcut64 = d64 / bits64; + h64 = dcut64; + data64 = (uint64_t *)(target + 8); + *data64 = htole64(h64); + dcut64 = h64; + dcut64 *= bits64; + d64 -= dcut64; + + h64 = d64; + data64 = (uint64_t *)(target); + *data64 = htole64(h64); +} diff --git a/src/libckpool.h b/src/libckpool.h index 8a19018a..9927da61 100644 --- a/src/libckpool.h +++ b/src/libckpool.h @@ -139,5 +139,11 @@ void cksleep_us(int64_t us); double us_tvdiff(tv_t *end, tv_t *start); int ms_tvdiff(tv_t *end, tv_t *start); double tvdiff(tv_t *end, tv_t *start); +void decay_time(double *f, double fadd, double fsecs, double interval); +void suffix_string(double val, char *buf, size_t bufsiz, int sigdigits); +double le256todouble(const uchar *target); +double diff_from_target(uchar *target); +double diff_from_header(uchar *header); +void target_from_diff(uchar *target, double diff); #endif /* LIBCKPOOL_H */